summaryrefslogtreecommitdiff
path: root/src/protocol/messages.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/protocol/messages.rs')
-rw-r--r--src/protocol/messages.rs863
1 files changed, 863 insertions, 0 deletions
diff --git a/src/protocol/messages.rs b/src/protocol/messages.rs
new file mode 100644
index 0000000..106f136
--- /dev/null
+++ b/src/protocol/messages.rs
@@ -0,0 +1,863 @@
+// Copyright 2018 The ChromiumOS Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::io;
+use std::io::ErrorKind;
+use std::io::Read;
+use std::io::Write;
+use std::mem;
+use std::string::String;
+use std::vec::Vec;
+
+use crate::protocol::wire_format::Data;
+use crate::protocol::wire_format::WireFormat;
+
+// Message type constants. Taken from "include/net/9p/9p.h" in the linux kernel
+// tree. The protocol specifies each R* message to be the corresponding T*
+// message plus one.
+const TLERROR: u8 = 6;
+const RLERROR: u8 = TLERROR + 1;
+const TSTATFS: u8 = 8;
+const RSTATFS: u8 = TSTATFS + 1;
+const TLOPEN: u8 = 12;
+const RLOPEN: u8 = TLOPEN + 1;
+const TLCREATE: u8 = 14;
+const RLCREATE: u8 = TLCREATE + 1;
+const TSYMLINK: u8 = 16;
+const RSYMLINK: u8 = TSYMLINK + 1;
+const TMKNOD: u8 = 18;
+const RMKNOD: u8 = TMKNOD + 1;
+const TRENAME: u8 = 20;
+const RRENAME: u8 = TRENAME + 1;
+const TREADLINK: u8 = 22;
+const RREADLINK: u8 = TREADLINK + 1;
+const TGETATTR: u8 = 24;
+const RGETATTR: u8 = TGETATTR + 1;
+const TSETATTR: u8 = 26;
+const RSETATTR: u8 = TSETATTR + 1;
+const TXATTRWALK: u8 = 30;
+const RXATTRWALK: u8 = TXATTRWALK + 1;
+const TXATTRCREATE: u8 = 32;
+const RXATTRCREATE: u8 = TXATTRCREATE + 1;
+const TREADDIR: u8 = 40;
+const RREADDIR: u8 = TREADDIR + 1;
+const TFSYNC: u8 = 50;
+const RFSYNC: u8 = TFSYNC + 1;
+const TLOCK: u8 = 52;
+const RLOCK: u8 = TLOCK + 1;
+const TGETLOCK: u8 = 54;
+const RGETLOCK: u8 = TGETLOCK + 1;
+const TLINK: u8 = 70;
+const RLINK: u8 = TLINK + 1;
+const TMKDIR: u8 = 72;
+const RMKDIR: u8 = TMKDIR + 1;
+const TRENAMEAT: u8 = 74;
+const RRENAMEAT: u8 = TRENAMEAT + 1;
+const TUNLINKAT: u8 = 76;
+const RUNLINKAT: u8 = TUNLINKAT + 1;
+const TVERSION: u8 = 100;
+const RVERSION: u8 = TVERSION + 1;
+const TAUTH: u8 = 102;
+const RAUTH: u8 = TAUTH + 1;
+const TATTACH: u8 = 104;
+const RATTACH: u8 = TATTACH + 1;
+const _TERROR: u8 = 106;
+const _RERROR: u8 = _TERROR + 1;
+const TFLUSH: u8 = 108;
+const RFLUSH: u8 = TFLUSH + 1;
+const TWALK: u8 = 110;
+const RWALK: u8 = TWALK + 1;
+const _TOPEN: u8 = 112;
+const _ROPEN: u8 = _TOPEN + 1;
+const _TCREATE: u8 = 114;
+const _RCREATE: u8 = _TCREATE + 1;
+const TREAD: u8 = 116;
+const RREAD: u8 = TREAD + 1;
+const TWRITE: u8 = 118;
+const RWRITE: u8 = TWRITE + 1;
+const TCLUNK: u8 = 120;
+const RCLUNK: u8 = TCLUNK + 1;
+const TREMOVE: u8 = 122;
+const RREMOVE: u8 = TREMOVE + 1;
+const _TSTAT: u8 = 124;
+const _RSTAT: u8 = _TSTAT + 1;
+const _TWSTAT: u8 = 126;
+const _RWSTAT: u8 = _TWSTAT + 1;
+
+/// A message sent from a 9P client to a 9P server.
+#[derive(Debug)]
+pub enum Tmessage {
+ Version(Tversion),
+ Flush(Tflush),
+ Walk(Twalk),
+ Read(Tread),
+ Write(Twrite),
+ Clunk(Tclunk),
+ Remove(Tremove),
+ Attach(Tattach),
+ Auth(Tauth),
+ Statfs(Tstatfs),
+ Lopen(Tlopen),
+ Lcreate(Tlcreate),
+ Symlink(Tsymlink),
+ Mknod(Tmknod),
+ Rename(Trename),
+ Readlink(Treadlink),
+ GetAttr(Tgetattr),
+ SetAttr(Tsetattr),
+ XattrWalk(Txattrwalk),
+ XattrCreate(Txattrcreate),
+ Readdir(Treaddir),
+ Fsync(Tfsync),
+ Lock(Tlock),
+ GetLock(Tgetlock),
+ Link(Tlink),
+ Mkdir(Tmkdir),
+ RenameAt(Trenameat),
+ UnlinkAt(Tunlinkat),
+}
+
+#[derive(Debug)]
+pub struct Tframe {
+ pub tag: u16,
+ pub msg: io::Result<Tmessage>,
+}
+
+impl WireFormat for Tframe {
+ fn byte_size(&self) -> u32 {
+ let msg = self
+ .msg
+ .as_ref()
+ .expect("tried to encode Tframe with invalid msg");
+ let msg_size = match msg {
+ Tmessage::Version(ref version) => version.byte_size(),
+ Tmessage::Flush(ref flush) => flush.byte_size(),
+ Tmessage::Walk(ref walk) => walk.byte_size(),
+ Tmessage::Read(ref read) => read.byte_size(),
+ Tmessage::Write(ref write) => write.byte_size(),
+ Tmessage::Clunk(ref clunk) => clunk.byte_size(),
+ Tmessage::Remove(ref remove) => remove.byte_size(),
+ Tmessage::Attach(ref attach) => attach.byte_size(),
+ Tmessage::Auth(ref auth) => auth.byte_size(),
+ Tmessage::Statfs(ref statfs) => statfs.byte_size(),
+ Tmessage::Lopen(ref lopen) => lopen.byte_size(),
+ Tmessage::Lcreate(ref lcreate) => lcreate.byte_size(),
+ Tmessage::Symlink(ref symlink) => symlink.byte_size(),
+ Tmessage::Mknod(ref mknod) => mknod.byte_size(),
+ Tmessage::Rename(ref rename) => rename.byte_size(),
+ Tmessage::Readlink(ref readlink) => readlink.byte_size(),
+ Tmessage::GetAttr(ref getattr) => getattr.byte_size(),
+ Tmessage::SetAttr(ref setattr) => setattr.byte_size(),
+ Tmessage::XattrWalk(ref xattrwalk) => xattrwalk.byte_size(),
+ Tmessage::XattrCreate(ref xattrcreate) => xattrcreate.byte_size(),
+ Tmessage::Readdir(ref readdir) => readdir.byte_size(),
+ Tmessage::Fsync(ref fsync) => fsync.byte_size(),
+ Tmessage::Lock(ref lock) => lock.byte_size(),
+ Tmessage::GetLock(ref getlock) => getlock.byte_size(),
+ Tmessage::Link(ref link) => link.byte_size(),
+ Tmessage::Mkdir(ref mkdir) => mkdir.byte_size(),
+ Tmessage::RenameAt(ref renameat) => renameat.byte_size(),
+ Tmessage::UnlinkAt(ref unlinkat) => unlinkat.byte_size(),
+ };
+
+ // size + type + tag + message size
+ (mem::size_of::<u32>() + mem::size_of::<u8>() + mem::size_of::<u16>()) as u32 + msg_size
+ }
+
+ fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
+ let msg = match self.msg.as_ref() {
+ Ok(msg) => msg,
+ Err(_) => {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidData,
+ "tried to encode Tframe with invalid msg",
+ ))
+ }
+ };
+
+ self.byte_size().encode(writer)?;
+
+ let ty = match msg {
+ Tmessage::Version(_) => TVERSION,
+ Tmessage::Flush(_) => TFLUSH,
+ Tmessage::Walk(_) => TWALK,
+ Tmessage::Read(_) => TREAD,
+ Tmessage::Write(_) => TWRITE,
+ Tmessage::Clunk(_) => TCLUNK,
+ Tmessage::Remove(_) => TREMOVE,
+ Tmessage::Attach(_) => TATTACH,
+ Tmessage::Auth(_) => TAUTH,
+ Tmessage::Statfs(_) => TSTATFS,
+ Tmessage::Lopen(_) => TLOPEN,
+ Tmessage::Lcreate(_) => TLCREATE,
+ Tmessage::Symlink(_) => TSYMLINK,
+ Tmessage::Mknod(_) => TMKNOD,
+ Tmessage::Rename(_) => TRENAME,
+ Tmessage::Readlink(_) => TREADLINK,
+ Tmessage::GetAttr(_) => TGETATTR,
+ Tmessage::SetAttr(_) => TSETATTR,
+ Tmessage::XattrWalk(_) => TXATTRWALK,
+ Tmessage::XattrCreate(_) => TXATTRCREATE,
+ Tmessage::Readdir(_) => TREADDIR,
+ Tmessage::Fsync(_) => TFSYNC,
+ Tmessage::Lock(_) => TLOCK,
+ Tmessage::GetLock(_) => TGETLOCK,
+ Tmessage::Link(_) => TLINK,
+ Tmessage::Mkdir(_) => TMKDIR,
+ Tmessage::RenameAt(_) => TRENAMEAT,
+ Tmessage::UnlinkAt(_) => TUNLINKAT,
+ };
+
+ ty.encode(writer)?;
+ self.tag.encode(writer)?;
+
+ match msg {
+ Tmessage::Version(ref version) => version.encode(writer),
+ Tmessage::Flush(ref flush) => flush.encode(writer),
+ Tmessage::Walk(ref walk) => walk.encode(writer),
+ Tmessage::Read(ref read) => read.encode(writer),
+ Tmessage::Write(ref write) => write.encode(writer),
+ Tmessage::Clunk(ref clunk) => clunk.encode(writer),
+ Tmessage::Remove(ref remove) => remove.encode(writer),
+ Tmessage::Attach(ref attach) => attach.encode(writer),
+ Tmessage::Auth(ref auth) => auth.encode(writer),
+ Tmessage::Statfs(ref statfs) => statfs.encode(writer),
+ Tmessage::Lopen(ref lopen) => lopen.encode(writer),
+ Tmessage::Lcreate(ref lcreate) => lcreate.encode(writer),
+ Tmessage::Symlink(ref symlink) => symlink.encode(writer),
+ Tmessage::Mknod(ref mknod) => mknod.encode(writer),
+ Tmessage::Rename(ref rename) => rename.encode(writer),
+ Tmessage::Readlink(ref readlink) => readlink.encode(writer),
+ Tmessage::GetAttr(ref getattr) => getattr.encode(writer),
+ Tmessage::SetAttr(ref setattr) => setattr.encode(writer),
+ Tmessage::XattrWalk(ref xattrwalk) => xattrwalk.encode(writer),
+ Tmessage::XattrCreate(ref xattrcreate) => xattrcreate.encode(writer),
+ Tmessage::Readdir(ref readdir) => readdir.encode(writer),
+ Tmessage::Fsync(ref fsync) => fsync.encode(writer),
+ Tmessage::Lock(ref lock) => lock.encode(writer),
+ Tmessage::GetLock(ref getlock) => getlock.encode(writer),
+ Tmessage::Link(ref link) => link.encode(writer),
+ Tmessage::Mkdir(ref mkdir) => mkdir.encode(writer),
+ Tmessage::RenameAt(ref renameat) => renameat.encode(writer),
+ Tmessage::UnlinkAt(ref unlinkat) => unlinkat.encode(writer),
+ }
+ }
+
+ fn decode<R: Read>(reader: &mut R) -> io::Result<Self> {
+ let byte_size: u32 = WireFormat::decode(reader)?;
+
+ // byte_size includes the size of byte_size so remove that from the
+ // expected length of the message. Also make sure that byte_size is at least
+ // that long to begin with.
+ if byte_size < mem::size_of::<u32>() as u32 {
+ return Err(io::Error::new(
+ ErrorKind::InvalidData,
+ format!("byte_size(= {}) is less than 4 bytes", byte_size),
+ ));
+ }
+
+ let reader = &mut reader.take((byte_size - mem::size_of::<u32>() as u32) as u64);
+
+ let mut ty = [0u8];
+ reader.read_exact(&mut ty)?;
+
+ let tag: u16 = WireFormat::decode(reader)?;
+ let msg = Self::decode_message(reader, ty[0]);
+
+ Ok(Tframe { tag, msg })
+ }
+}
+
+impl Tframe {
+ fn decode_message<R: Read>(reader: &mut R, ty: u8) -> io::Result<Tmessage> {
+ match ty {
+ TVERSION => Ok(Tmessage::Version(WireFormat::decode(reader)?)),
+ TFLUSH => Ok(Tmessage::Flush(WireFormat::decode(reader)?)),
+ TWALK => Ok(Tmessage::Walk(WireFormat::decode(reader)?)),
+ TREAD => Ok(Tmessage::Read(WireFormat::decode(reader)?)),
+ TWRITE => Ok(Tmessage::Write(WireFormat::decode(reader)?)),
+ TCLUNK => Ok(Tmessage::Clunk(WireFormat::decode(reader)?)),
+ TREMOVE => Ok(Tmessage::Remove(WireFormat::decode(reader)?)),
+ TATTACH => Ok(Tmessage::Attach(WireFormat::decode(reader)?)),
+ TAUTH => Ok(Tmessage::Auth(WireFormat::decode(reader)?)),
+ TSTATFS => Ok(Tmessage::Statfs(WireFormat::decode(reader)?)),
+ TLOPEN => Ok(Tmessage::Lopen(WireFormat::decode(reader)?)),
+ TLCREATE => Ok(Tmessage::Lcreate(WireFormat::decode(reader)?)),
+ TSYMLINK => Ok(Tmessage::Symlink(WireFormat::decode(reader)?)),
+ TMKNOD => Ok(Tmessage::Mknod(WireFormat::decode(reader)?)),
+ TRENAME => Ok(Tmessage::Rename(WireFormat::decode(reader)?)),
+ TREADLINK => Ok(Tmessage::Readlink(WireFormat::decode(reader)?)),
+ TGETATTR => Ok(Tmessage::GetAttr(WireFormat::decode(reader)?)),
+ TSETATTR => Ok(Tmessage::SetAttr(WireFormat::decode(reader)?)),
+ TXATTRWALK => Ok(Tmessage::XattrWalk(WireFormat::decode(reader)?)),
+ TXATTRCREATE => Ok(Tmessage::XattrCreate(WireFormat::decode(reader)?)),
+ TREADDIR => Ok(Tmessage::Readdir(WireFormat::decode(reader)?)),
+ TFSYNC => Ok(Tmessage::Fsync(WireFormat::decode(reader)?)),
+ TLOCK => Ok(Tmessage::Lock(WireFormat::decode(reader)?)),
+ TGETLOCK => Ok(Tmessage::GetLock(WireFormat::decode(reader)?)),
+ TLINK => Ok(Tmessage::Link(WireFormat::decode(reader)?)),
+ TMKDIR => Ok(Tmessage::Mkdir(WireFormat::decode(reader)?)),
+ TRENAMEAT => Ok(Tmessage::RenameAt(WireFormat::decode(reader)?)),
+ TUNLINKAT => Ok(Tmessage::UnlinkAt(WireFormat::decode(reader)?)),
+ err => Err(io::Error::new(
+ ErrorKind::InvalidData,
+ format!("unknown message type {}", err),
+ )),
+ }
+ }
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tversion {
+ pub msize: u32,
+ pub version: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tflush {
+ pub oldtag: u16,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Twalk {
+ pub fid: u32,
+ pub newfid: u32,
+ pub wnames: Vec<String>,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tread {
+ pub fid: u32,
+ pub offset: u64,
+ pub count: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Twrite {
+ pub fid: u32,
+ pub offset: u64,
+ pub data: Data,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tclunk {
+ pub fid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tremove {
+ pub fid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tauth {
+ pub afid: u32,
+ pub uname: String,
+ pub aname: String,
+ pub n_uname: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tattach {
+ pub fid: u32,
+ pub afid: u32,
+ pub uname: String,
+ pub aname: String,
+ pub n_uname: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tstatfs {
+ pub fid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tlopen {
+ pub fid: u32,
+ pub flags: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tlcreate {
+ pub fid: u32,
+ pub name: String,
+ pub flags: u32,
+ pub mode: u32,
+ pub gid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tsymlink {
+ pub fid: u32,
+ pub name: String,
+ pub symtgt: String,
+ pub gid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tmknod {
+ pub dfid: u32,
+ pub name: String,
+ pub mode: u32,
+ pub major: u32,
+ pub minor: u32,
+ pub gid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Trename {
+ pub fid: u32,
+ pub dfid: u32,
+ pub name: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Treadlink {
+ pub fid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tgetattr {
+ pub fid: u32,
+ pub request_mask: u64,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tsetattr {
+ pub fid: u32,
+ pub valid: u32,
+ pub mode: u32,
+ pub uid: u32,
+ pub gid: u32,
+ pub size: u64,
+ pub atime_sec: u64,
+ pub atime_nsec: u64,
+ pub mtime_sec: u64,
+ pub mtime_nsec: u64,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Txattrwalk {
+ pub fid: u32,
+ pub newfid: u32,
+ pub name: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Txattrcreate {
+ pub fid: u32,
+ pub name: String,
+ pub attr_size: u64,
+ pub flags: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Treaddir {
+ pub fid: u32,
+ pub offset: u64,
+ pub count: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tfsync {
+ pub fid: u32,
+ pub datasync: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tlock {
+ pub fid: u32,
+ pub type_: u8,
+ pub flags: u32,
+ pub start: u64,
+ pub length: u64,
+ pub proc_id: u32,
+ pub client_id: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tgetlock {
+ pub fid: u32,
+ pub type_: u8,
+ pub start: u64,
+ pub length: u64,
+ pub proc_id: u32,
+ pub client_id: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tlink {
+ pub dfid: u32,
+ pub fid: u32,
+ pub name: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tmkdir {
+ pub dfid: u32,
+ pub name: String,
+ pub mode: u32,
+ pub gid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Trenameat {
+ pub olddirfid: u32,
+ pub oldname: String,
+ pub newdirfid: u32,
+ pub newname: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tunlinkat {
+ pub dirfd: u32,
+ pub name: String,
+ pub flags: u32,
+}
+
+/// A message sent from a 9P server to a 9P client in response to a request from
+/// that client. Encapsulates a full frame.
+#[derive(Debug)]
+pub enum Rmessage {
+ Version(Rversion),
+ Flush,
+ Walk(Rwalk),
+ Read(Rread),
+ Write(Rwrite),
+ Clunk,
+ Remove,
+ Attach(Rattach),
+ Auth(Rauth),
+ Statfs(Rstatfs),
+ Lopen(Rlopen),
+ Lcreate(Rlcreate),
+ Symlink(Rsymlink),
+ Mknod(Rmknod),
+ Rename,
+ Readlink(Rreadlink),
+ GetAttr(Rgetattr),
+ SetAttr,
+ XattrWalk(Rxattrwalk),
+ XattrCreate,
+ Readdir(Rreaddir),
+ Fsync,
+ Lock(Rlock),
+ GetLock(Rgetlock),
+ Link,
+ Mkdir(Rmkdir),
+ RenameAt,
+ UnlinkAt,
+ Lerror(Rlerror),
+}
+
+#[derive(Debug)]
+pub struct Rframe {
+ pub tag: u16,
+ pub msg: Rmessage,
+}
+
+impl WireFormat for Rframe {
+ fn byte_size(&self) -> u32 {
+ let msg_size = match self.msg {
+ Rmessage::Version(ref version) => version.byte_size(),
+ Rmessage::Flush => 0,
+ Rmessage::Walk(ref walk) => walk.byte_size(),
+ Rmessage::Read(ref read) => read.byte_size(),
+ Rmessage::Write(ref write) => write.byte_size(),
+ Rmessage::Clunk => 0,
+ Rmessage::Remove => 0,
+ Rmessage::Attach(ref attach) => attach.byte_size(),
+ Rmessage::Auth(ref auth) => auth.byte_size(),
+ Rmessage::Statfs(ref statfs) => statfs.byte_size(),
+ Rmessage::Lopen(ref lopen) => lopen.byte_size(),
+ Rmessage::Lcreate(ref lcreate) => lcreate.byte_size(),
+ Rmessage::Symlink(ref symlink) => symlink.byte_size(),
+ Rmessage::Mknod(ref mknod) => mknod.byte_size(),
+ Rmessage::Rename => 0,
+ Rmessage::Readlink(ref readlink) => readlink.byte_size(),
+ Rmessage::GetAttr(ref getattr) => getattr.byte_size(),
+ Rmessage::SetAttr => 0,
+ Rmessage::XattrWalk(ref xattrwalk) => xattrwalk.byte_size(),
+ Rmessage::XattrCreate => 0,
+ Rmessage::Readdir(ref readdir) => readdir.byte_size(),
+ Rmessage::Fsync => 0,
+ Rmessage::Lock(ref lock) => lock.byte_size(),
+ Rmessage::GetLock(ref getlock) => getlock.byte_size(),
+ Rmessage::Link => 0,
+ Rmessage::Mkdir(ref mkdir) => mkdir.byte_size(),
+ Rmessage::RenameAt => 0,
+ Rmessage::UnlinkAt => 0,
+ Rmessage::Lerror(ref lerror) => lerror.byte_size(),
+ };
+
+ // size + type + tag + message size
+ (mem::size_of::<u32>() + mem::size_of::<u8>() + mem::size_of::<u16>()) as u32 + msg_size
+ }
+
+ fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
+ self.byte_size().encode(writer)?;
+
+ let ty = match self.msg {
+ Rmessage::Version(_) => RVERSION,
+ Rmessage::Flush => RFLUSH,
+ Rmessage::Walk(_) => RWALK,
+ Rmessage::Read(_) => RREAD,
+ Rmessage::Write(_) => RWRITE,
+ Rmessage::Clunk => RCLUNK,
+ Rmessage::Remove => RREMOVE,
+ Rmessage::Attach(_) => RATTACH,
+ Rmessage::Auth(_) => RAUTH,
+ Rmessage::Statfs(_) => RSTATFS,
+ Rmessage::Lopen(_) => RLOPEN,
+ Rmessage::Lcreate(_) => RLCREATE,
+ Rmessage::Symlink(_) => RSYMLINK,
+ Rmessage::Mknod(_) => RMKNOD,
+ Rmessage::Rename => RRENAME,
+ Rmessage::Readlink(_) => RREADLINK,
+ Rmessage::GetAttr(_) => RGETATTR,
+ Rmessage::SetAttr => RSETATTR,
+ Rmessage::XattrWalk(_) => RXATTRWALK,
+ Rmessage::XattrCreate => RXATTRCREATE,
+ Rmessage::Readdir(_) => RREADDIR,
+ Rmessage::Fsync => RFSYNC,
+ Rmessage::Lock(_) => RLOCK,
+ Rmessage::GetLock(_) => RGETLOCK,
+ Rmessage::Link => RLINK,
+ Rmessage::Mkdir(_) => RMKDIR,
+ Rmessage::RenameAt => RRENAMEAT,
+ Rmessage::UnlinkAt => RUNLINKAT,
+ Rmessage::Lerror(_) => RLERROR,
+ };
+
+ ty.encode(writer)?;
+ self.tag.encode(writer)?;
+
+ match self.msg {
+ Rmessage::Version(ref version) => version.encode(writer),
+ Rmessage::Flush => Ok(()),
+ Rmessage::Walk(ref walk) => walk.encode(writer),
+ Rmessage::Read(ref read) => read.encode(writer),
+ Rmessage::Write(ref write) => write.encode(writer),
+ Rmessage::Clunk => Ok(()),
+ Rmessage::Remove => Ok(()),
+ Rmessage::Attach(ref attach) => attach.encode(writer),
+ Rmessage::Auth(ref auth) => auth.encode(writer),
+ Rmessage::Statfs(ref statfs) => statfs.encode(writer),
+ Rmessage::Lopen(ref lopen) => lopen.encode(writer),
+ Rmessage::Lcreate(ref lcreate) => lcreate.encode(writer),
+ Rmessage::Symlink(ref symlink) => symlink.encode(writer),
+ Rmessage::Mknod(ref mknod) => mknod.encode(writer),
+ Rmessage::Rename => Ok(()),
+ Rmessage::Readlink(ref readlink) => readlink.encode(writer),
+ Rmessage::GetAttr(ref getattr) => getattr.encode(writer),
+ Rmessage::SetAttr => Ok(()),
+ Rmessage::XattrWalk(ref xattrwalk) => xattrwalk.encode(writer),
+ Rmessage::XattrCreate => Ok(()),
+ Rmessage::Readdir(ref readdir) => readdir.encode(writer),
+ Rmessage::Fsync => Ok(()),
+ Rmessage::Lock(ref lock) => lock.encode(writer),
+ Rmessage::GetLock(ref getlock) => getlock.encode(writer),
+ Rmessage::Link => Ok(()),
+ Rmessage::Mkdir(ref mkdir) => mkdir.encode(writer),
+ Rmessage::RenameAt => Ok(()),
+ Rmessage::UnlinkAt => Ok(()),
+ Rmessage::Lerror(ref lerror) => lerror.encode(writer),
+ }
+ }
+
+ fn decode<R: Read>(reader: &mut R) -> io::Result<Self> {
+ let byte_size: u32 = WireFormat::decode(reader)?;
+
+ // byte_size includes the size of byte_size so remove that from the
+ // expected length of the message.
+ let reader = &mut reader.take((byte_size - mem::size_of::<u32>() as u32) as u64);
+
+ let mut ty = [0u8];
+ reader.read_exact(&mut ty)?;
+
+ let tag: u16 = WireFormat::decode(reader)?;
+
+ let msg = match ty[0] {
+ RVERSION => Ok(Rmessage::Version(WireFormat::decode(reader)?)),
+ RFLUSH => Ok(Rmessage::Flush),
+ RWALK => Ok(Rmessage::Walk(WireFormat::decode(reader)?)),
+ RREAD => Ok(Rmessage::Read(WireFormat::decode(reader)?)),
+ RWRITE => Ok(Rmessage::Write(WireFormat::decode(reader)?)),
+ RCLUNK => Ok(Rmessage::Clunk),
+ RREMOVE => Ok(Rmessage::Remove),
+ RATTACH => Ok(Rmessage::Attach(WireFormat::decode(reader)?)),
+ RAUTH => Ok(Rmessage::Auth(WireFormat::decode(reader)?)),
+ RSTATFS => Ok(Rmessage::Statfs(WireFormat::decode(reader)?)),
+ RLOPEN => Ok(Rmessage::Lopen(WireFormat::decode(reader)?)),
+ RLCREATE => Ok(Rmessage::Lcreate(WireFormat::decode(reader)?)),
+ RSYMLINK => Ok(Rmessage::Symlink(WireFormat::decode(reader)?)),
+ RMKNOD => Ok(Rmessage::Mknod(WireFormat::decode(reader)?)),
+ RRENAME => Ok(Rmessage::Rename),
+ RREADLINK => Ok(Rmessage::Readlink(WireFormat::decode(reader)?)),
+ RGETATTR => Ok(Rmessage::GetAttr(WireFormat::decode(reader)?)),
+ RSETATTR => Ok(Rmessage::SetAttr),
+ RXATTRWALK => Ok(Rmessage::XattrWalk(WireFormat::decode(reader)?)),
+ RXATTRCREATE => Ok(Rmessage::XattrCreate),
+ RREADDIR => Ok(Rmessage::Readdir(WireFormat::decode(reader)?)),
+ RFSYNC => Ok(Rmessage::Fsync),
+ RLOCK => Ok(Rmessage::Lock(WireFormat::decode(reader)?)),
+ RGETLOCK => Ok(Rmessage::GetLock(WireFormat::decode(reader)?)),
+ RLINK => Ok(Rmessage::Link),
+ RMKDIR => Ok(Rmessage::Mkdir(WireFormat::decode(reader)?)),
+ RRENAMEAT => Ok(Rmessage::RenameAt),
+ RUNLINKAT => Ok(Rmessage::UnlinkAt),
+ RLERROR => Ok(Rmessage::Lerror(WireFormat::decode(reader)?)),
+ err => Err(io::Error::new(
+ ErrorKind::InvalidData,
+ format!("unknown message type {}", err),
+ )),
+ }?;
+
+ Ok(Rframe { tag, msg })
+ }
+}
+
+#[derive(Debug, Copy, Clone, P9WireFormat)]
+pub struct Qid {
+ pub ty: u8,
+ pub version: u32,
+ pub path: u64,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Dirent {
+ pub qid: Qid,
+ pub offset: u64,
+ pub ty: u8,
+ pub name: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rversion {
+ pub msize: u32,
+ pub version: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rwalk {
+ pub wqids: Vec<Qid>,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rread {
+ pub data: Data,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rwrite {
+ pub count: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rauth {
+ pub aqid: Qid,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rattach {
+ pub qid: Qid,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rlerror {
+ pub ecode: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rstatfs {
+ pub ty: u32,
+ pub bsize: u32,
+ pub blocks: u64,
+ pub bfree: u64,
+ pub bavail: u64,
+ pub files: u64,
+ pub ffree: u64,
+ pub fsid: u64,
+ pub namelen: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rlopen {
+ pub qid: Qid,
+ pub iounit: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rlcreate {
+ pub qid: Qid,
+ pub iounit: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rsymlink {
+ pub qid: Qid,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rmknod {
+ pub qid: Qid,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rreadlink {
+ pub target: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rgetattr {
+ pub valid: u64,
+ pub qid: Qid,
+ pub mode: u32,
+ pub uid: u32,
+ pub gid: u32,
+ pub nlink: u64,
+ pub rdev: u64,
+ pub size: u64,
+ pub blksize: u64,
+ pub blocks: u64,
+ pub atime_sec: u64,
+ pub atime_nsec: u64,
+ pub mtime_sec: u64,
+ pub mtime_nsec: u64,
+ pub ctime_sec: u64,
+ pub ctime_nsec: u64,
+ pub btime_sec: u64,
+ pub btime_nsec: u64,
+ pub gen: u64,
+ pub data_version: u64,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rxattrwalk {
+ pub size: u64,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rreaddir {
+ pub data: Data,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rlock {
+ pub status: u8,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rgetlock {
+ pub type_: u8,
+ pub start: u64,
+ pub length: u64,
+ pub proc_id: u32,
+ pub client_id: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rmkdir {
+ pub qid: Qid,
+}