1
// Copyright (c) 2024, Sevki <s@sevki.io>
2
// Copyright 2018 The ChromiumOS Authors
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
5

            
6
use {
7
    jetstream_macros::JetStreamWireFormat,
8
    jetstream_rpc::Message,
9
    jetstream_wireformat::{Data, WireFormat},
10
    std::{
11
        io,
12
        io::{ErrorKind, Read, Write},
13
        mem,
14
        string::String,
15
        vec::Vec,
16
    },
17
};
18

            
19
use crate::{P9_QTDIR, P9_QTFILE, P9_QTSYMLINK};
20

            
21
impl Message for Tframe {}
22
impl Message for Rframe {}
23

            
24
// Message type constants.  Taken from "include/net/9p/9p.h" in the linux kernel
25
// tree.  The protocol specifies each R* message to be the corresponding T*
26
// message plus one.
27
const TLERROR: u8 = 6;
28
const RLERROR: u8 = TLERROR + 1;
29
const TSTATFS: u8 = 8;
30
const RSTATFS: u8 = TSTATFS + 1;
31
const TLOPEN: u8 = 12;
32
const RLOPEN: u8 = TLOPEN + 1;
33
const TLCREATE: u8 = 14;
34
const RLCREATE: u8 = TLCREATE + 1;
35
const TSYMLINK: u8 = 16;
36
const RSYMLINK: u8 = TSYMLINK + 1;
37
const TMKNOD: u8 = 18;
38
const RMKNOD: u8 = TMKNOD + 1;
39
const TRENAME: u8 = 20;
40
const RRENAME: u8 = TRENAME + 1;
41
const TREADLINK: u8 = 22;
42
const RREADLINK: u8 = TREADLINK + 1;
43
const TGETATTR: u8 = 24;
44
const RGETATTR: u8 = TGETATTR + 1;
45
const TSETATTR: u8 = 26;
46
const RSETATTR: u8 = TSETATTR + 1;
47
const TXATTRWALK: u8 = 30;
48
const RXATTRWALK: u8 = TXATTRWALK + 1;
49
const TXATTRCREATE: u8 = 32;
50
const RXATTRCREATE: u8 = TXATTRCREATE + 1;
51
const TREADDIR: u8 = 40;
52
const RREADDIR: u8 = TREADDIR + 1;
53
const TFSYNC: u8 = 50;
54
const RFSYNC: u8 = TFSYNC + 1;
55
const TLOCK: u8 = 52;
56
const RLOCK: u8 = TLOCK + 1;
57
const TGETLOCK: u8 = 54;
58
const RGETLOCK: u8 = TGETLOCK + 1;
59
const TLINK: u8 = 70;
60
const RLINK: u8 = TLINK + 1;
61
const TMKDIR: u8 = 72;
62
const RMKDIR: u8 = TMKDIR + 1;
63
const TRENAMEAT: u8 = 74;
64
const RRENAMEAT: u8 = TRENAMEAT + 1;
65
const TUNLINKAT: u8 = 76;
66
const RUNLINKAT: u8 = TUNLINKAT + 1;
67
const TVERSION: u8 = 100;
68
const RVERSION: u8 = TVERSION + 1;
69
const TAUTH: u8 = 102;
70
const RAUTH: u8 = TAUTH + 1;
71
const TATTACH: u8 = 104;
72
const RATTACH: u8 = TATTACH + 1;
73
const _TERROR: u8 = 106;
74
const _RERROR: u8 = _TERROR + 1;
75
const TFLUSH: u8 = 108;
76
const RFLUSH: u8 = TFLUSH + 1;
77
const TWALK: u8 = 110;
78
const RWALK: u8 = TWALK + 1;
79
const _TOPEN: u8 = 112;
80
const _ROPEN: u8 = _TOPEN + 1;
81
const _TCREATE: u8 = 114;
82
const _RCREATE: u8 = _TCREATE + 1;
83
const TREAD: u8 = 116;
84
const RREAD: u8 = TREAD + 1;
85
const TWRITE: u8 = 118;
86
const RWRITE: u8 = TWRITE + 1;
87
const TCLUNK: u8 = 120;
88
const RCLUNK: u8 = TCLUNK + 1;
89
const TREMOVE: u8 = 122;
90
const RREMOVE: u8 = TREMOVE + 1;
91
const _TSTAT: u8 = 124;
92
const _RSTAT: u8 = _TSTAT + 1;
93
const _TWSTAT: u8 = 126;
94
const _RWSTAT: u8 = _TWSTAT + 1;
95

            
96
/// A message sent from a 9P client to a 9P server.
97
#[derive(Debug)]
98
#[repr(u8)]
99
pub enum Tmessage {
100
    Version(Tversion) = TVERSION,
101
    Flush(Tflush) = TFLUSH,
102
    Walk(Twalk) = TWALK,
103
    Read(Tread) = TREAD,
104
    Write(Twrite) = TWRITE,
105
    Clunk(Tclunk) = TCLUNK,
106
    Remove(Tremove) = TREMOVE,
107
    Attach(Tattach) = TATTACH,
108
    Auth(Tauth) = TAUTH,
109
    Statfs(Tstatfs) = TSTATFS,
110
    Lopen(Tlopen) = TLOPEN,
111
    Lcreate(Tlcreate) = TLCREATE,
112
    Symlink(Tsymlink) = TSYMLINK,
113
    Mknod(Tmknod) = TMKNOD,
114
    Rename(Trename) = TRENAME,
115
    Readlink(Treadlink) = TREADLINK,
116
    GetAttr(Tgetattr) = TGETATTR,
117
    SetAttr(Tsetattr) = TSETATTR,
118
    XattrWalk(Txattrwalk) = TXATTRWALK,
119
    XattrCreate(Txattrcreate) = TXATTRCREATE,
120
    Readdir(Treaddir) = TREADDIR,
121
    Fsync(Tfsync) = TFSYNC,
122
    Lock(Tlock) = TLOCK,
123
    GetLock(Tgetlock) = TGETLOCK,
124
    Link(Tlink) = TLINK,
125
    Mkdir(Tmkdir) = TMKDIR,
126
    RenameAt(Trenameat) = TRENAMEAT,
127
    UnlinkAt(Tunlinkat) = TUNLINKAT,
128
}
129

            
130
#[derive(Debug)]
131
pub struct Tframe {
132
    pub tag: u16,
133
    pub msg: io::Result<Tmessage>,
134
}
135

            
136
impl WireFormat for Tframe {
137
6
    fn byte_size(&self) -> u32 {
138
6
        let msg = self
139
6
            .msg
140
6
            .as_ref()
141
6
            .expect("tried to encode Tframe with invalid msg");
142
6
        let msg_size = match msg {
143
6
            Tmessage::Version(ref version) => version.byte_size(),
144
            Tmessage::Flush(ref flush) => flush.byte_size(),
145
            Tmessage::Walk(ref walk) => walk.byte_size(),
146
            Tmessage::Read(ref read) => read.byte_size(),
147
            Tmessage::Write(ref write) => write.byte_size(),
148
            Tmessage::Clunk(ref clunk) => clunk.byte_size(),
149
            Tmessage::Remove(ref remove) => remove.byte_size(),
150
            Tmessage::Attach(ref attach) => attach.byte_size(),
151
            Tmessage::Auth(ref auth) => auth.byte_size(),
152
            Tmessage::Statfs(ref statfs) => statfs.byte_size(),
153
            Tmessage::Lopen(ref lopen) => lopen.byte_size(),
154
            Tmessage::Lcreate(ref lcreate) => lcreate.byte_size(),
155
            Tmessage::Symlink(ref symlink) => symlink.byte_size(),
156
            Tmessage::Mknod(ref mknod) => mknod.byte_size(),
157
            Tmessage::Rename(ref rename) => rename.byte_size(),
158
            Tmessage::Readlink(ref readlink) => readlink.byte_size(),
159
            Tmessage::GetAttr(ref getattr) => getattr.byte_size(),
160
            Tmessage::SetAttr(ref setattr) => setattr.byte_size(),
161
            Tmessage::XattrWalk(ref xattrwalk) => xattrwalk.byte_size(),
162
            Tmessage::XattrCreate(ref xattrcreate) => xattrcreate.byte_size(),
163
            Tmessage::Readdir(ref readdir) => readdir.byte_size(),
164
            Tmessage::Fsync(ref fsync) => fsync.byte_size(),
165
            Tmessage::Lock(ref lock) => lock.byte_size(),
166
            Tmessage::GetLock(ref getlock) => getlock.byte_size(),
167
            Tmessage::Link(ref link) => link.byte_size(),
168
            Tmessage::Mkdir(ref mkdir) => mkdir.byte_size(),
169
            Tmessage::RenameAt(ref renameat) => renameat.byte_size(),
170
            Tmessage::UnlinkAt(ref unlinkat) => unlinkat.byte_size(),
171
        };
172

            
173
        // size + type + tag + message size
174
6
        (mem::size_of::<u32>() + mem::size_of::<u8>() + mem::size_of::<u16>()) as u32 + msg_size
175
6
    }
176

            
177
6
    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
178
6
        let msg = match self.msg.as_ref() {
179
6
            Ok(msg) => msg,
180
            Err(_) => {
181
                return Err(io::Error::new(
182
                    io::ErrorKind::InvalidData,
183
                    "tried to encode Tframe with invalid msg",
184
                ))
185
            }
186
        };
187

            
188
6
        self.byte_size().encode(writer)?;
189

            
190
6
        let ty = match msg {
191
6
            Tmessage::Version(_) => TVERSION,
192
            Tmessage::Flush(_) => TFLUSH,
193
            Tmessage::Walk(_) => TWALK,
194
            Tmessage::Read(_) => TREAD,
195
            Tmessage::Write(_) => TWRITE,
196
            Tmessage::Clunk(_) => TCLUNK,
197
            Tmessage::Remove(_) => TREMOVE,
198
            Tmessage::Attach(_) => TATTACH,
199
            Tmessage::Auth(_) => TAUTH,
200
            Tmessage::Statfs(_) => TSTATFS,
201
            Tmessage::Lopen(_) => TLOPEN,
202
            Tmessage::Lcreate(_) => TLCREATE,
203
            Tmessage::Symlink(_) => TSYMLINK,
204
            Tmessage::Mknod(_) => TMKNOD,
205
            Tmessage::Rename(_) => TRENAME,
206
            Tmessage::Readlink(_) => TREADLINK,
207
            Tmessage::GetAttr(_) => TGETATTR,
208
            Tmessage::SetAttr(_) => TSETATTR,
209
            Tmessage::XattrWalk(_) => TXATTRWALK,
210
            Tmessage::XattrCreate(_) => TXATTRCREATE,
211
            Tmessage::Readdir(_) => TREADDIR,
212
            Tmessage::Fsync(_) => TFSYNC,
213
            Tmessage::Lock(_) => TLOCK,
214
            Tmessage::GetLock(_) => TGETLOCK,
215
            Tmessage::Link(_) => TLINK,
216
            Tmessage::Mkdir(_) => TMKDIR,
217
            Tmessage::RenameAt(_) => TRENAMEAT,
218
            Tmessage::UnlinkAt(_) => TUNLINKAT,
219
        };
220

            
221
6
        ty.encode(writer)?;
222
6
        self.tag.encode(writer)?;
223

            
224
6
        match msg {
225
6
            Tmessage::Version(ref version) => version.encode(writer),
226
            Tmessage::Flush(ref flush) => flush.encode(writer),
227
            Tmessage::Walk(ref walk) => walk.encode(writer),
228
            Tmessage::Read(ref read) => read.encode(writer),
229
            Tmessage::Write(ref write) => write.encode(writer),
230
            Tmessage::Clunk(ref clunk) => clunk.encode(writer),
231
            Tmessage::Remove(ref remove) => remove.encode(writer),
232
            Tmessage::Attach(ref attach) => attach.encode(writer),
233
            Tmessage::Auth(ref auth) => auth.encode(writer),
234
            Tmessage::Statfs(ref statfs) => statfs.encode(writer),
235
            Tmessage::Lopen(ref lopen) => lopen.encode(writer),
236
            Tmessage::Lcreate(ref lcreate) => lcreate.encode(writer),
237
            Tmessage::Symlink(ref symlink) => symlink.encode(writer),
238
            Tmessage::Mknod(ref mknod) => mknod.encode(writer),
239
            Tmessage::Rename(ref rename) => rename.encode(writer),
240
            Tmessage::Readlink(ref readlink) => readlink.encode(writer),
241
            Tmessage::GetAttr(ref getattr) => getattr.encode(writer),
242
            Tmessage::SetAttr(ref setattr) => setattr.encode(writer),
243
            Tmessage::XattrWalk(ref xattrwalk) => xattrwalk.encode(writer),
244
            Tmessage::XattrCreate(ref xattrcreate) => xattrcreate.encode(writer),
245
            Tmessage::Readdir(ref readdir) => readdir.encode(writer),
246
            Tmessage::Fsync(ref fsync) => fsync.encode(writer),
247
            Tmessage::Lock(ref lock) => lock.encode(writer),
248
            Tmessage::GetLock(ref getlock) => getlock.encode(writer),
249
            Tmessage::Link(ref link) => link.encode(writer),
250
            Tmessage::Mkdir(ref mkdir) => mkdir.encode(writer),
251
            Tmessage::RenameAt(ref renameat) => renameat.encode(writer),
252
            Tmessage::UnlinkAt(ref unlinkat) => unlinkat.encode(writer),
253
        }
254
6
    }
255

            
256
6
    fn decode<R: Read>(reader: &mut R) -> io::Result<Self> {
257
6
        let byte_size: u32 = WireFormat::decode(reader)?;
258

            
259
        // byte_size includes the size of byte_size so remove that from the
260
        // expected length of the message.  Also make sure that byte_size is at least
261
        // that long to begin with.
262
6
        if byte_size < mem::size_of::<u32>() as u32 {
263
            return Err(io::Error::new(
264
                ErrorKind::InvalidData,
265
                format!("byte_size(= {}) is less than 4 bytes", byte_size),
266
            ));
267
6
        }
268
6

            
269
6
        let reader = &mut reader.take((byte_size - mem::size_of::<u32>() as u32) as u64);
270
6

            
271
6
        let mut ty = [0u8];
272
6
        reader.read_exact(&mut ty)?;
273

            
274
6
        let tag: u16 = WireFormat::decode(reader)?;
275
6
        let msg = Self::decode_message(reader, ty[0]);
276
6

            
277
6
        Ok(Tframe { tag, msg })
278
6
    }
279
}
280

            
281
impl Tframe {
282
6
    fn decode_message<R: Read>(reader: &mut R, ty: u8) -> io::Result<Tmessage> {
283
6
        match ty {
284
6
            TVERSION => Ok(Tmessage::Version(WireFormat::decode(reader)?)),
285
            TFLUSH => Ok(Tmessage::Flush(WireFormat::decode(reader)?)),
286
            TWALK => Ok(Tmessage::Walk(WireFormat::decode(reader)?)),
287
            TREAD => Ok(Tmessage::Read(WireFormat::decode(reader)?)),
288
            TWRITE => Ok(Tmessage::Write(WireFormat::decode(reader)?)),
289
            TCLUNK => Ok(Tmessage::Clunk(WireFormat::decode(reader)?)),
290
            TREMOVE => Ok(Tmessage::Remove(WireFormat::decode(reader)?)),
291
            TATTACH => Ok(Tmessage::Attach(WireFormat::decode(reader)?)),
292
            TAUTH => Ok(Tmessage::Auth(WireFormat::decode(reader)?)),
293
            TSTATFS => Ok(Tmessage::Statfs(WireFormat::decode(reader)?)),
294
            TLOPEN => Ok(Tmessage::Lopen(WireFormat::decode(reader)?)),
295
            TLCREATE => Ok(Tmessage::Lcreate(WireFormat::decode(reader)?)),
296
            TSYMLINK => Ok(Tmessage::Symlink(WireFormat::decode(reader)?)),
297
            TMKNOD => Ok(Tmessage::Mknod(WireFormat::decode(reader)?)),
298
            TRENAME => Ok(Tmessage::Rename(WireFormat::decode(reader)?)),
299
            TREADLINK => Ok(Tmessage::Readlink(WireFormat::decode(reader)?)),
300
            TGETATTR => Ok(Tmessage::GetAttr(WireFormat::decode(reader)?)),
301
            TSETATTR => Ok(Tmessage::SetAttr(WireFormat::decode(reader)?)),
302
            TXATTRWALK => Ok(Tmessage::XattrWalk(WireFormat::decode(reader)?)),
303
            TXATTRCREATE => Ok(Tmessage::XattrCreate(WireFormat::decode(reader)?)),
304
            TREADDIR => Ok(Tmessage::Readdir(WireFormat::decode(reader)?)),
305
            TFSYNC => Ok(Tmessage::Fsync(WireFormat::decode(reader)?)),
306
            TLOCK => Ok(Tmessage::Lock(WireFormat::decode(reader)?)),
307
            TGETLOCK => Ok(Tmessage::GetLock(WireFormat::decode(reader)?)),
308
            TLINK => Ok(Tmessage::Link(WireFormat::decode(reader)?)),
309
            TMKDIR => Ok(Tmessage::Mkdir(WireFormat::decode(reader)?)),
310
            TRENAMEAT => Ok(Tmessage::RenameAt(WireFormat::decode(reader)?)),
311
            TUNLINKAT => Ok(Tmessage::UnlinkAt(WireFormat::decode(reader)?)),
312
            err => {
313
                Err(io::Error::new(
314
                    ErrorKind::InvalidData,
315
                    format!("unknown message type {}", err),
316
                ))
317
            }
318
        }
319
6
    }
320
}
321

            
322
/// A message sent from a 9P server to a 9P client in response to a request from
323
/// that client.  Encapsulates a full frame.
324
#[derive(Debug)]
325
pub enum Rmessage {
326
    Version(Rversion),
327
    Flush,
328
    Walk(Rwalk),
329
    Read(Rread),
330
    Write(Rwrite),
331
    Clunk,
332
    Remove,
333
    Attach(Rattach),
334
    Auth(Rauth),
335
    Statfs(Rstatfs),
336
    Lopen(Rlopen),
337
    Lcreate(Rlcreate),
338
    Symlink(Rsymlink),
339
    Mknod(Rmknod),
340
    Rename,
341
    Readlink(Rreadlink),
342
    GetAttr(Rgetattr),
343
    SetAttr,
344
    XattrWalk(Rxattrwalk),
345
    XattrCreate,
346
    Readdir(Rreaddir),
347
    Fsync,
348
    Lock(Rlock),
349
    GetLock(Rgetlock),
350
    Link,
351
    Mkdir(Rmkdir),
352
    RenameAt,
353
    UnlinkAt,
354
    Lerror(Rlerror),
355
}
356

            
357
#[derive(Debug)]
358
pub struct Rframe {
359
    pub tag: u16,
360
    pub msg: Rmessage,
361
}
362

            
363
impl WireFormat for Rframe {
364
    fn byte_size(&self) -> u32 {
365
        let msg_size = match self.msg {
366
            Rmessage::Version(ref version) => version.byte_size(),
367
            Rmessage::Flush => 0,
368
            Rmessage::Walk(ref walk) => walk.byte_size(),
369
            Rmessage::Read(ref read) => read.byte_size(),
370
            Rmessage::Write(ref write) => write.byte_size(),
371
            Rmessage::Clunk => 0,
372
            Rmessage::Remove => 0,
373
            Rmessage::Attach(ref attach) => attach.byte_size(),
374
            Rmessage::Auth(ref auth) => auth.byte_size(),
375
            Rmessage::Statfs(ref statfs) => statfs.byte_size(),
376
            Rmessage::Lopen(ref lopen) => lopen.byte_size(),
377
            Rmessage::Lcreate(ref lcreate) => lcreate.byte_size(),
378
            Rmessage::Symlink(ref symlink) => symlink.byte_size(),
379
            Rmessage::Mknod(ref mknod) => mknod.byte_size(),
380
            Rmessage::Rename => 0,
381
            Rmessage::Readlink(ref readlink) => readlink.byte_size(),
382
            Rmessage::GetAttr(ref getattr) => getattr.byte_size(),
383
            Rmessage::SetAttr => 0,
384
            Rmessage::XattrWalk(ref xattrwalk) => xattrwalk.byte_size(),
385
            Rmessage::XattrCreate => 0,
386
            Rmessage::Readdir(ref readdir) => readdir.byte_size(),
387
            Rmessage::Fsync => 0,
388
            Rmessage::Lock(ref lock) => lock.byte_size(),
389
            Rmessage::GetLock(ref getlock) => getlock.byte_size(),
390
            Rmessage::Link => 0,
391
            Rmessage::Mkdir(ref mkdir) => mkdir.byte_size(),
392
            Rmessage::RenameAt => 0,
393
            Rmessage::UnlinkAt => 0,
394
            Rmessage::Lerror(ref lerror) => lerror.byte_size(),
395
        };
396

            
397
        // size + type + tag + message size
398
        (mem::size_of::<u32>() + mem::size_of::<u8>() + mem::size_of::<u16>()) as u32 + msg_size
399
    }
400

            
401
    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
402
        self.byte_size().encode(writer)?;
403

            
404
        let ty = match self.msg {
405
            Rmessage::Version(_) => RVERSION,
406
            Rmessage::Flush => RFLUSH,
407
            Rmessage::Walk(_) => RWALK,
408
            Rmessage::Read(_) => RREAD,
409
            Rmessage::Write(_) => RWRITE,
410
            Rmessage::Clunk => RCLUNK,
411
            Rmessage::Remove => RREMOVE,
412
            Rmessage::Attach(_) => RATTACH,
413
            Rmessage::Auth(_) => RAUTH,
414
            Rmessage::Statfs(_) => RSTATFS,
415
            Rmessage::Lopen(_) => RLOPEN,
416
            Rmessage::Lcreate(_) => RLCREATE,
417
            Rmessage::Symlink(_) => RSYMLINK,
418
            Rmessage::Mknod(_) => RMKNOD,
419
            Rmessage::Rename => RRENAME,
420
            Rmessage::Readlink(_) => RREADLINK,
421
            Rmessage::GetAttr(_) => RGETATTR,
422
            Rmessage::SetAttr => RSETATTR,
423
            Rmessage::XattrWalk(_) => RXATTRWALK,
424
            Rmessage::XattrCreate => RXATTRCREATE,
425
            Rmessage::Readdir(_) => RREADDIR,
426
            Rmessage::Fsync => RFSYNC,
427
            Rmessage::Lock(_) => RLOCK,
428
            Rmessage::GetLock(_) => RGETLOCK,
429
            Rmessage::Link => RLINK,
430
            Rmessage::Mkdir(_) => RMKDIR,
431
            Rmessage::RenameAt => RRENAMEAT,
432
            Rmessage::UnlinkAt => RUNLINKAT,
433
            Rmessage::Lerror(_) => RLERROR,
434
        };
435

            
436
        ty.encode(writer)?;
437
        self.tag.encode(writer)?;
438

            
439
        match self.msg {
440
            Rmessage::Version(ref version) => version.encode(writer),
441
            Rmessage::Flush => Ok(()),
442
            Rmessage::Walk(ref walk) => walk.encode(writer),
443
            Rmessage::Read(ref read) => read.encode(writer),
444
            Rmessage::Write(ref write) => write.encode(writer),
445
            Rmessage::Clunk => Ok(()),
446
            Rmessage::Remove => Ok(()),
447
            Rmessage::Attach(ref attach) => attach.encode(writer),
448
            Rmessage::Auth(ref auth) => auth.encode(writer),
449
            Rmessage::Statfs(ref statfs) => statfs.encode(writer),
450
            Rmessage::Lopen(ref lopen) => lopen.encode(writer),
451
            Rmessage::Lcreate(ref lcreate) => lcreate.encode(writer),
452
            Rmessage::Symlink(ref symlink) => symlink.encode(writer),
453
            Rmessage::Mknod(ref mknod) => mknod.encode(writer),
454
            Rmessage::Rename => Ok(()),
455
            Rmessage::Readlink(ref readlink) => readlink.encode(writer),
456
            Rmessage::GetAttr(ref getattr) => getattr.encode(writer),
457
            Rmessage::SetAttr => Ok(()),
458
            Rmessage::XattrWalk(ref xattrwalk) => xattrwalk.encode(writer),
459
            Rmessage::XattrCreate => Ok(()),
460
            Rmessage::Readdir(ref readdir) => readdir.encode(writer),
461
            Rmessage::Fsync => Ok(()),
462
            Rmessage::Lock(ref lock) => lock.encode(writer),
463
            Rmessage::GetLock(ref getlock) => getlock.encode(writer),
464
            Rmessage::Link => Ok(()),
465
            Rmessage::Mkdir(ref mkdir) => mkdir.encode(writer),
466
            Rmessage::RenameAt => Ok(()),
467
            Rmessage::UnlinkAt => Ok(()),
468
            Rmessage::Lerror(ref lerror) => lerror.encode(writer),
469
        }
470
    }
471

            
472
    fn decode<R: Read>(reader: &mut R) -> io::Result<Self> {
473
        let byte_size: u32 = WireFormat::decode(reader)?;
474

            
475
        // byte_size includes the size of byte_size so remove that from the
476
        // expected length of the message.
477
        let reader = &mut reader.take((byte_size - mem::size_of::<u32>() as u32) as u64);
478

            
479
        let mut ty = [0u8];
480
        reader.read_exact(&mut ty)?;
481

            
482
        let tag: u16 = WireFormat::decode(reader)?;
483

            
484
        let msg = match ty[0] {
485
            RVERSION => Ok(Rmessage::Version(WireFormat::decode(reader)?)),
486
            RFLUSH => Ok(Rmessage::Flush),
487
            RWALK => Ok(Rmessage::Walk(WireFormat::decode(reader)?)),
488
            RREAD => Ok(Rmessage::Read(WireFormat::decode(reader)?)),
489
            RWRITE => Ok(Rmessage::Write(WireFormat::decode(reader)?)),
490
            RCLUNK => Ok(Rmessage::Clunk),
491
            RREMOVE => Ok(Rmessage::Remove),
492
            RATTACH => Ok(Rmessage::Attach(WireFormat::decode(reader)?)),
493
            RAUTH => Ok(Rmessage::Auth(WireFormat::decode(reader)?)),
494
            RSTATFS => Ok(Rmessage::Statfs(WireFormat::decode(reader)?)),
495
            RLOPEN => Ok(Rmessage::Lopen(WireFormat::decode(reader)?)),
496
            RLCREATE => Ok(Rmessage::Lcreate(WireFormat::decode(reader)?)),
497
            RSYMLINK => Ok(Rmessage::Symlink(WireFormat::decode(reader)?)),
498
            RMKNOD => Ok(Rmessage::Mknod(WireFormat::decode(reader)?)),
499
            RRENAME => Ok(Rmessage::Rename),
500
            RREADLINK => Ok(Rmessage::Readlink(WireFormat::decode(reader)?)),
501
            RGETATTR => Ok(Rmessage::GetAttr(WireFormat::decode(reader)?)),
502
            RSETATTR => Ok(Rmessage::SetAttr),
503
            RXATTRWALK => Ok(Rmessage::XattrWalk(WireFormat::decode(reader)?)),
504
            RXATTRCREATE => Ok(Rmessage::XattrCreate),
505
            RREADDIR => Ok(Rmessage::Readdir(WireFormat::decode(reader)?)),
506
            RFSYNC => Ok(Rmessage::Fsync),
507
            RLOCK => Ok(Rmessage::Lock(WireFormat::decode(reader)?)),
508
            RGETLOCK => Ok(Rmessage::GetLock(WireFormat::decode(reader)?)),
509
            RLINK => Ok(Rmessage::Link),
510
            RMKDIR => Ok(Rmessage::Mkdir(WireFormat::decode(reader)?)),
511
            RRENAMEAT => Ok(Rmessage::RenameAt),
512
            RUNLINKAT => Ok(Rmessage::UnlinkAt),
513
            RLERROR => Ok(Rmessage::Lerror(WireFormat::decode(reader)?)),
514
            err => {
515
                Err(io::Error::new(
516
                    ErrorKind::InvalidData,
517
                    format!("unknown message type {}", err),
518
                ))
519
            }
520
        }?;
521

            
522
        Ok(Rframe { tag, msg })
523
    }
524
}
525

            
526
/// version -- negotiate protocol version
527
///
528
/// ```text
529
/// size[4] Tversion tag[2] msize[4] version[s]
530
/// size[4] Rversion tag[2] msize[4] version[s]
531
/// ```
532
///
533
/// version establishes the msize, which is the maximum message size inclusive of the size value that can be handled by both client and server.
534
///
535
/// It also establishes the protocol version. For 9P2000.L version must be the string 9P2000.L.
536
///
537
/// See the Plan 9 manual page for [version(5)](http://9p.io/magic/man2html/5/version).
538
6
#[derive(Debug, JetStreamWireFormat)]
539
pub struct Tversion {
540
    pub msize: u32,
541
    pub version: String,
542
}
543

            
544
/// flush -- abort a message
545
///
546
/// ```text
547
/// size[4] Tflush tag[2] oldtag[2]
548
/// size[4] Rflush tag[2]
549
/// ```
550
///
551
/// flush aborts an in-flight request referenced by oldtag, if any.
552
///
553
/// See the Plan 9 manual page for [flush(5)](http://9p.io/magic/man2html/5/flush).
554
#[derive(Debug, JetStreamWireFormat)]
555
pub struct Tflush {
556
    pub oldtag: u16,
557
}
558

            
559
/// walk -- descend a directory hierarchy
560
///
561
/// ```text
562
/// size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s])
563
/// size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13])
564
/// ```
565
///
566
/// walk is used to descend a directory represented by fid using successive path elements provided in the wname array. If successful, newfid represents the new path.
567
///
568
/// fid can be cloned to newfid by calling walk with nwname set to zero.
569
///
570
/// See the Plan 9 manual page for [walk(5)](http://9p.io/magic/man2html/5/walk).
571
#[derive(Debug, JetStreamWireFormat)]
572
pub struct Twalk {
573
    pub fid: u32,
574
    pub newfid: u32,
575
    pub wnames: Vec<String>,
576
}
577

            
578
/// attach -- attach to a file tree
579
///
580
/// ```text
581
/// size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s]
582
/// size[4] Rattach tag[2] qid[13]
583
/// ```
584
///
585
/// attach associates the fid with the file tree rooted at aname.
586
#[derive(Debug, JetStreamWireFormat)]
587
pub struct Tattach {
588
    pub fid: u32,
589
    pub afid: u32,
590
    pub uname: String,
591
    pub aname: String,
592
    pub n_uname: u32,
593
}
594

            
595
/// auth -- authenticate a user
596
///
597
/// ```text
598
/// size[4] Tauth tag[2] afid[4] uname[s] aname[s]
599
/// size[4] Rauth tag[2] aqid[13]
600
/// ```
601
///
602
/// auth authenticates the user named uname to access the file tree with the root named aname.
603
///
604
/// afid is used as the fid in the attach message that follows auth.
605
#[derive(Debug, JetStreamWireFormat)]
606
pub struct Tauth {
607
    pub afid: u32,
608
    pub uname: String,
609
    pub aname: String,
610
    pub n_uname: u32,
611
}
612

            
613
/// read -- read data from a file
614
///
615
/// ```text
616
/// size[4] Tread tag[2] fid[4] offset[8] count[4]
617
/// size[4] Rread tag[2] count[4] data[count]
618
/// ```
619
///
620
/// read performs I/O on the file represented by fid.
621
///
622
/// Under 9P2000.L, read cannot be used on directories. See [Treaddir](struct.Treaddir.html) for reading directories.
623
///
624
/// See the Plan 9 manual page for [read(5)](http://9p.io/magic/man2html/5/read).
625
#[derive(Debug, JetStreamWireFormat)]
626
pub struct Tread {
627
    pub fid: u32,
628
    pub offset: u64,
629
    pub count: u32,
630
}
631

            
632
#[derive(Debug, JetStreamWireFormat)]
633
pub struct Rread {
634
    pub data: Data,
635
}
636

            
637
/// write -- write data to a file
638
///
639
/// ```text
640
/// size[4] Twrite tag[2] fid[4] offset[8] data[count]
641
/// size[4] Rwrite tag[2] count[4]
642
/// ```
643
///
644
/// write performs I/O on the file represented by fid.
645
///
646
/// See the Plan 9 manual page for [write(5)](http://9p.io/magic/man2html/5/write).
647
#[derive(Debug, JetStreamWireFormat)]
648
pub struct Twrite {
649
    pub fid: u32,
650
    pub offset: u64,
651
    pub data: Data,
652
}
653

            
654
#[derive(Debug, JetStreamWireFormat)]
655
pub struct Rwrite {
656
    pub count: u32,
657
}
658

            
659
/// clunk -- remove fid
660
///
661
/// ```text
662
/// size[4] Tclunk tag[2] fid[4]
663
/// size[4] Rclunk tag[2]
664
/// ```
665
///
666
/// clunk removes the fid from the fid table.
667
///
668
/// See the Plan 9 manual page for [clunk(5)](http://9p.io/magic/man2html/5/clunk).
669
#[derive(Debug, JetStreamWireFormat)]
670
pub struct Tclunk {
671
    pub fid: u32,
672
}
673

            
674
/// remove -- remove a file
675
///
676
/// ```text
677
/// size[4] Tremove tag[2] fid[4]
678
/// size[4] Rremove tag[2]
679
/// ```
680
///
681
/// remove removes the file represented by fid.
682
///
683
/// See the Plan 9 manual page for [remove(5)](http://9p.io/magic/man2html/5/remove).
684
#[derive(Debug, JetStreamWireFormat)]
685
pub struct Tremove {
686
    pub fid: u32,
687
}
688

            
689
/// statfs -- get file system information
690
///
691
/// ```text
692
/// size[4] Tstatfs tag[2] fid[4]
693
/// size[4] Rstatfs tag[2] type[4] bsize[4] blocks[8] bfree[8] bavail[8]
694
///                        files[8] ffree[8] fsid[8] namelen[4]
695
/// ```
696
///
697
/// statfs is used to request file system information of the file system containing fid.
698
/// The Rstatfs response corresponds to the fields returned by the statfs(2) system call.
699
#[derive(Debug, JetStreamWireFormat)]
700
pub struct Tstatfs {
701
    pub fid: u32,
702
}
703

            
704
#[derive(Debug, JetStreamWireFormat)]
705
pub struct Rstatfs {
706
    pub ty: u32,
707
    pub bsize: u32,
708
    pub blocks: u64,
709
    pub bfree: u64,
710
    pub bavail: u64,
711
    pub files: u64,
712
    pub ffree: u64,
713
    pub fsid: u64,
714
    pub namelen: u32,
715
}
716

            
717
/// lopen -- open a file
718
///
719
/// ```text
720
/// size[4] Tlopen tag[2] fid[4] flags[4]
721
/// size[4] Rlopen tag[2] qid[13] iounit[4]
722
/// ```
723
///
724
/// lopen prepares fid for file I/O. The flags field has the standard open(2) values.
725
#[derive(Debug, JetStreamWireFormat)]
726
pub struct Tlopen {
727
    pub fid: u32,
728
    pub flags: u32,
729
}
730

            
731
#[derive(Debug, JetStreamWireFormat)]
732
pub struct Rlopen {
733
    pub qid: Qid,
734
    pub iounit: u32,
735
}
736

            
737
/// lcreate -- create a file
738
///
739
/// ```text
740
/// size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4]
741
/// size[4] Rlcreate tag[2] qid[13] iounit[4]
742
/// ```
743
///
744
/// lcreate creates a new file name in the directory represented by fid and prepares it for I/O.
745
/// The flags field has the standard open(2) values.
746
#[derive(Debug, JetStreamWireFormat)]
747
pub struct Tlcreate {
748
    pub fid: u32,
749
    pub name: String,
750
    pub flags: u32,
751
    pub mode: u32,
752
    pub gid: u32,
753
}
754

            
755
#[derive(Debug, JetStreamWireFormat)]
756
pub struct Rlcreate {
757
    pub qid: Qid,
758
    pub iounit: u32,
759
}
760

            
761
/// symlink -- create symlink
762
///
763
/// ```text
764
/// size[4] Tsymlink tag[2] fid[4] name[s] symtgt[s] gid[4]
765
/// size[4] Rsymlink tag[2] qid[13]
766
/// ```
767
///
768
/// symlink creates a new symbolic link name in the directory represented by fid.
769
#[derive(Debug, JetStreamWireFormat)]
770
pub struct Tsymlink {
771
    pub fid: u32,
772
    pub name: String,
773
    pub symtgt: String,
774
    pub gid: u32,
775
}
776

            
777
#[derive(Debug, JetStreamWireFormat)]
778
pub struct Rsymlink {
779
    pub qid: Qid,
780
}
781

            
782
/// mknod -- create a special file
783
///
784
/// ```text
785
/// size[4] Tmknod tag[2] dfid[4] name[s] mode[4] major[4] minor[4] gid[4]
786
/// size[4] Rmknod tag[2] qid[13]
787
/// ```
788
///
789
/// mknod creates a new special file name in the directory represented by dfid.
790
#[derive(Debug, JetStreamWireFormat)]
791
pub struct Tmknod {
792
    pub dfid: u32,
793
    pub name: String,
794
    pub mode: u32,
795
    pub major: u32,
796
    pub minor: u32,
797
    pub gid: u32,
798
}
799

            
800
#[derive(Debug, JetStreamWireFormat)]
801
pub struct Rmknod {
802
    pub qid: Qid,
803
}
804

            
805
/// rename -- rename a file
806
///
807
/// ```text
808
/// size[4] Trename tag[2] fid[4] dfid[4] name[s]
809
/// size[4] Rrename tag[2]
810
/// ```
811
///
812
/// rename renames a file or directory from old name to new name in the
813
/// directory represented by dfid. fid represents the file to be renamed.
814
#[derive(Debug, JetStreamWireFormat)]
815
pub struct Trename {
816
    pub fid: u32,
817
    pub dfid: u32,
818
    pub name: String,
819
}
820

            
821
/// readlink -- read symlink value
822
///
823
/// ```text
824
/// size[4] Treadlink tag[2] fid[4]
825
/// size[4] Rreadlink tag[2] target[s]
826
/// ```
827
///
828
/// readlink reads the target of the symbolic link represented by fid.
829
#[derive(Debug, JetStreamWireFormat)]
830
pub struct Treadlink {
831
    pub fid: u32,
832
}
833

            
834
#[derive(Debug, JetStreamWireFormat)]
835
pub struct Rreadlink {
836
    pub target: String,
837
}
838

            
839
/// getattr -- get file attributes
840
///
841
/// ```text
842
/// size[4] Tgetattr tag[2] fid[4] request_mask[8]
843
/// size[4] Rgetattr tag[2] valid[8] qid[13] mode[4] uid[4] gid[4] nlink[8]
844
///     rdev[8] size[8] blksize[8] blocks[8] atime_sec[8] atime_nsec[8]
845
///     mtime_sec[8] mtime_nsec[8] ctime_sec[8] ctime_nsec[8] btime_sec[8]
846
///     btime_nsec[8] gen[8] data_version[8]
847
/// ```
848
///
849
/// getattr gets attributes of the file system object represented by fid.
850
#[derive(Debug, JetStreamWireFormat)]
851
pub struct Tgetattr {
852
    pub fid: u32,
853
    pub request_mask: u64,
854
}
855

            
856
#[derive(Debug, JetStreamWireFormat)]
857
pub struct Rgetattr {
858
    pub valid: u64,
859
    pub qid: Qid,
860
    pub mode: u32,
861
    pub uid: u32,
862
    pub gid: u32,
863
    pub nlink: u64,
864
    pub rdev: u64,
865
    pub size: u64,
866
    pub blksize: u64,
867
    pub blocks: u64,
868
    pub atime_sec: u64,
869
    pub atime_nsec: u64,
870
    pub mtime_sec: u64,
871
    pub mtime_nsec: u64,
872
    pub ctime_sec: u64,
873
    pub ctime_nsec: u64,
874
    pub btime_sec: u64,
875
    pub btime_nsec: u64,
876
    pub gen: u64,
877
    pub data_version: u64,
878
}
879

            
880
/// setattr -- set file attributes
881
///
882
/// ```text
883
/// size[4] Tsetattr tag[2] fid[4] valid[4] mode[4] uid[4] gid[4] size[8]
884
///     atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]
885
/// size[4] Rsetattr tag[2]
886
/// ```
887
///
888
/// setattr sets attributes of the file system object represented by fid.
889
#[derive(Debug, JetStreamWireFormat)]
890
pub struct Tsetattr {
891
    pub fid: u32,
892
    pub valid: u32,
893
    pub mode: u32,
894
    pub uid: u32,
895
    pub gid: u32,
896
    pub size: u64,
897
    pub atime_sec: u64,
898
    pub atime_nsec: u64,
899
    pub mtime_sec: u64,
900
    pub mtime_nsec: u64,
901
}
902

            
903
/// xattrwalk -- walk extended attributes
904
///
905
/// ```text
906
/// size[4] Txattrwalk tag[2] fid[4] newfid[4] name[s]
907
/// size[4] Rxattrwalk tag[2] size[8]
908
/// ```
909
///
910
/// xattrwalk gets a new fid pointing to the extended attribute directory
911
/// of the file represented by fid.
912
#[derive(Debug, JetStreamWireFormat)]
913
pub struct Txattrwalk {
914
    pub fid: u32,
915
    pub newfid: u32,
916
    pub name: String,
917
}
918

            
919
#[derive(Debug, JetStreamWireFormat)]
920
pub struct Rxattrwalk {
921
    pub size: u64,
922
}
923

            
924
/// xattrcreate -- create an extended attribute
925
///
926
/// ```text
927
/// size[4] Txattrcreate tag[2] fid[4] name[s] attr_size[8] flags[4]
928
/// size[4] Rxattrcreate tag[2]
929
/// ```
930
///
931
/// xattrcreate creates a new extended attribute named name of the file represented by fid.
932
#[derive(Debug, JetStreamWireFormat)]
933
pub struct Txattrcreate {
934
    pub fid: u32,
935
    pub name: String,
936
    pub attr_size: u64,
937
    pub flags: u32,
938
}
939

            
940
/// readdir -- read directory entries
941
///
942
/// ```text
943
/// size[4] Treaddir tag[2] fid[4] offset[8] count[4]
944
/// size[4] Rreaddir tag[2] count[4] data[count]
945
/// ```
946
///
947
/// readdir reads directory entries from the directory represented by fid.
948
#[derive(Debug, JetStreamWireFormat)]
949
pub struct Treaddir {
950
    pub fid: u32,
951
    pub offset: u64,
952
    pub count: u32,
953
}
954

            
955
#[derive(Debug, JetStreamWireFormat)]
956
pub struct Rreaddir {
957
    pub data: Data,
958
}
959

            
960
/// fsync -- synchronize file
961
///
962
/// ```text
963
/// size[4] Tfsync tag[2] fid[4] datasync[4]
964
/// size[4] Rfsync tag[2]
965
/// ```
966
///
967
/// fsync flushes any cached data and metadata for the file represented by fid to stable storage.
968
#[derive(Debug, JetStreamWireFormat)]
969
pub struct Tfsync {
970
    pub fid: u32,
971
    pub datasync: u32,
972
}
973

            
974
/// lock -- acquire or release a POSIX record lock
975
///
976
/// ```text
977
/// size[4] Tlock tag[2] fid[4] type[1] flags[4] start[8] length[8] proc_id[4] client_id[s]
978
/// size[4] Rlock tag[2] status[1]
979
/// ```
980
///
981
/// lock acquires or releases a POSIX record lock on the open file fid.
982
///
983
/// See the Plan 9 manual page for [lock(5)](http://9p.io/magic/man2html/5/lock).
984
#[derive(Debug, JetStreamWireFormat)]
985
pub struct Tlock {
986
    pub fid: u32,
987
    pub type_: u8,
988
    pub flags: u32,
989
    pub start: u64,
990
    pub length: u64,
991
    pub proc_id: u32,
992
    pub client_id: String,
993
}
994

            
995
#[derive(Debug, JetStreamWireFormat)]
996
pub struct Rlock {
997
    pub status: u8,
998
}
999

            
/// getlock -- test for the existence of a POSIX record lock
///
/// ```text
/// size[4] Tgetlock tag[2] fid[4] type[1] start[8] length[8] proc_id[4] client_id[s]
/// size[4] Rgetlock tag[2] type[1] start[8] length[8] proc_id[4] client_id[s]
/// ```
///
/// getlock tests for the existence of a POSIX record lock on the open file fid.
///
/// See the Plan 9 manual page for [getlock(5)](http://9p.io/magic/man2html/5/getlock).
#[derive(Debug, JetStreamWireFormat)]
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, JetStreamWireFormat)]
pub struct Rgetlock {
    pub type_: u8,
    pub start: u64,
    pub length: u64,
    pub proc_id: u32,
    pub client_id: String,
}
#[derive(Debug, JetStreamWireFormat)]
pub struct Rlerror {
    pub ecode: u32,
}
// Rerror
#[derive(Debug, JetStreamWireFormat)]
pub struct Rerror {
    pub ename: String,
}
/// link -- create hard link
///
/// ```text
/// size[4] Tlink tag[2] dfid[4] fid[4] name[s]
/// size[4] Rlink tag[2]
/// ```
///
/// link creates a new hard link name in the directory dfid that refers to the same file as fid.
#[derive(Debug, JetStreamWireFormat)]
pub struct Tlink {
    pub dfid: u32,
    pub fid: u32,
    pub name: String,
}
/// mkdir -- create directory
///
/// ```text
/// size[4] Tmkdir tag[2] dfid[4] name[s] mode[4] gid[4]
/// size[4] Rmkdir tag[2] qid[13]
/// ```
///
/// mkdir creates a new directory name in the directory represented by dfid.
#[derive(Debug, JetStreamWireFormat)]
pub struct Tmkdir {
    pub dfid: u32,
    pub name: String,
    pub mode: u32,
    pub gid: u32,
}
#[derive(Debug, JetStreamWireFormat)]
pub struct Rmkdir {
    pub qid: Qid,
}
/// renameat -- rename a file or directory
///
/// ```text
/// size[4] Trenameat tag[2] olddirfid[4] oldname[s] newdirfid[4] newname[s]
/// size[4] Rrenameat tag[2]
/// ```
///
/// renameat renames a file or directory from oldname in the directory represented by
/// olddirfid to newname in the directory represented by newdirfid.
#[derive(Debug, JetStreamWireFormat)]
pub struct Trenameat {
    pub olddirfid: u32,
    pub oldname: String,
    pub newdirfid: u32,
    pub newname: String,
}
/// unlinkat -- unlink a file or directory
///
/// ```text
/// size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4]
/// size[4] Runlinkat tag[2]
/// ```
///
/// unlinkat removes the file name from the directory represented by dirfd.
#[derive(Debug, JetStreamWireFormat)]
pub struct Tunlinkat {
    pub dirfd: u32,
    pub name: String,
    pub flags: u32,
}
/// Qid
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, JetStreamWireFormat)]
pub struct Qid {
    pub ty: u8,
    pub version: u32,
    pub path: u64,
}
impl From<libc::stat64> for Qid {
    fn from(st: libc::stat64) -> Qid {
        let ty = match st.st_mode & libc::S_IFMT {
            libc::S_IFDIR => P9_QTDIR,
            libc::S_IFREG => P9_QTFILE,
            libc::S_IFLNK => P9_QTSYMLINK,
            _ => 0,
        };
        Qid {
            ty,
            // TODO: deal with the 2038 problem before 2038
            version: st.st_mtime as u32,
            path: st.st_ino,
        }
    }
}
/// Dirent -- directory entry
#[derive(Debug, JetStreamWireFormat)]
pub struct Dirent {
    pub qid: Qid,
    pub offset: u64,
    pub ty: u8,
    pub name: String,
}
#[derive(Debug, JetStreamWireFormat)]
pub struct Rversion {
    pub msize: u32,
    pub version: String,
}
#[derive(Debug, JetStreamWireFormat)]
pub struct Rwalk {
    pub wqids: Vec<Qid>,
}
#[derive(Debug, JetStreamWireFormat)]
pub struct Rauth {
    pub aqid: Qid,
}
#[derive(Debug, JetStreamWireFormat)]
pub struct Rattach {
    pub qid: Qid,
}