diff --git a/p9/src/protocol/messages.rs b/p9/src/protocol/messages.rs new file mode 100644 index 0000000000..23f0d9f321 --- /dev/null +++ b/p9/src/protocol/messages.rs @@ -0,0 +1,840 @@ +// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use std::io::{self, ErrorKind, Read, Write}; +use std::mem; +use std::string::String; +use std::vec::Vec; + +use protocol::wire_format::{Data, 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: Tmessage, +} + +impl WireFormat for Tframe { + fn byte_size(&self) -> u32 { + let msg_size = match self.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::() + mem::size_of::() + mem::size_of::()) as u32 + msg_size + } + + fn encode(&self, writer: &mut W) -> io::Result<()> { + self.byte_size().encode(writer)?; + + let ty = match self.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 self.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(reader: &mut R) -> io::Result { + 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::() 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::() as u32) as u64); + + let mut ty = [0u8]; + reader.read_exact(&mut ty)?; + + let tag: u16 = WireFormat::decode(reader)?; + + let msg = match ty[0] { + 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), + )), + }?; + + Ok(Tframe { tag: tag, msg: msg }) + } +} + +#[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, +} + +#[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::() + mem::size_of::() + mem::size_of::()) as u32 + msg_size + } + + fn encode(&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(reader: &mut R) -> io::Result { + 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::() 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: tag, msg: 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, +} + +#[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 ty: u8, + pub start: u64, + pub length: u64, + pub proc_id: u32, + pub client_id: String, +} + +#[derive(Debug, P9WireFormat)] +pub struct Rmkdir { + pub qid: Qid, +} diff --git a/p9/src/protocol/mod.rs b/p9/src/protocol/mod.rs index 2e246e54bf..9c278ee893 100644 --- a/p9/src/protocol/mod.rs +++ b/p9/src/protocol/mod.rs @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +mod messages; mod wire_format; +pub use self::messages::*; pub use self::wire_format::{Data, WireFormat};