blob: b5a03c0727dba6fbaf4908e0fd9f055410789df7 [file] [log] [blame]
// 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 crate::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::<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 {
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<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 = 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, 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<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 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,
}