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 jetstream_libc as libc;
7
use std::{
8
    io,
9
    io::{ErrorKind, Read, Write},
10
    mem,
11
    string::String,
12
    vec::Vec,
13
};
14

            
15
use jetstream_macros::JetStreamWireFormat;
16
use jetstream_rpc::Message;
17
use jetstream_wireformat::{Data, WireFormat};
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
    fn byte_size(&self) -> u32 {
138
        let msg = self
139
            .msg
140
            .as_ref()
141
            .expect("tried to encode Tframe with invalid msg");
142
        let msg_size = match msg {
143
            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
        (mem::size_of::<u32>() + mem::size_of::<u8>() + mem::size_of::<u16>())
175
            as u32
176
            + msg_size
177
    }
178

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

            
190
        self.byte_size().encode(writer)?;
191

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

            
223
        ty.encode(writer)?;
224
        self.tag.encode(writer)?;
225

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

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

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

            
273
        let reader =
274
            &mut reader.take((byte_size - mem::size_of::<u32>() as u32) as u64);
275

            
276
        let mut ty = [0u8];
277
        reader.read_exact(&mut ty)?;
278

            
279
        let tag: u16 = WireFormat::decode(reader)?;
280
        let msg = Self::decode_message(reader, ty[0]);
281

            
282
        Ok(Tframe { tag, msg })
283
    }
284
}
285

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

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

            
362
#[derive(Debug)]
363
pub struct Rframe {
364
    pub tag: u16,
365
    pub msg: Rmessage,
366
}
367

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

            
402
        // size + type + tag + message size
403
        (mem::size_of::<u32>() + mem::size_of::<u8>() + mem::size_of::<u16>())
404
            as u32
405
            + msg_size
406
    }
407

            
408
    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
409
        self.byte_size().encode(writer)?;
410

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

            
443
        ty.encode(writer)?;
444
        self.tag.encode(writer)?;
445

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

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

            
482
        // byte_size includes the size of byte_size so remove that from the
483
        // expected length of the message.
484
        let reader =
485
            &mut reader.take((byte_size - mem::size_of::<u32>() as u32) as u64);
486

            
487
        let mut ty = [0u8];
488
        reader.read_exact(&mut ty)?;
489

            
490
        let tag: u16 = WireFormat::decode(reader)?;
491

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

            
528
        Ok(Rframe { tag, msg })
529
    }
530
}
531

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

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

            
565
/// walk -- descend a directory hierarchy
566
///
567
/// ```text
568
/// size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s])
569
/// size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13])
570
/// ```
571
///
572
/// 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.
573
///
574
/// fid can be cloned to newfid by calling walk with nwname set to zero.
575
///
576
/// See the Plan 9 manual page for [walk(5)](http://9p.io/magic/man2html/5/walk).
577
#[derive(Debug, JetStreamWireFormat)]
578
pub struct Twalk {
579
    pub fid: u32,
580
    pub newfid: u32,
581
    pub wnames: Vec<String>,
582
}
583

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

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

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

            
638
#[derive(Debug, JetStreamWireFormat)]
639
pub struct Rread {
640
    pub data: Data,
641
}
642

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

            
660
#[derive(Debug, JetStreamWireFormat)]
661
pub struct Rwrite {
662
    pub count: u32,
663
}
664

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

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

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

            
710
#[derive(Debug, JetStreamWireFormat)]
711
pub struct Rstatfs {
712
    pub ty: u32,
713
    pub bsize: u32,
714
    pub blocks: u64,
715
    pub bfree: u64,
716
    pub bavail: u64,
717
    pub files: u64,
718
    pub ffree: u64,
719
    pub fsid: u64,
720
    pub namelen: u32,
721
}
722

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

            
737
#[derive(Debug, JetStreamWireFormat)]
738
pub struct Rlopen {
739
    pub qid: Qid,
740
    pub iounit: u32,
741
}
742

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

            
761
#[derive(Debug, JetStreamWireFormat)]
762
pub struct Rlcreate {
763
    pub qid: Qid,
764
    pub iounit: u32,
765
}
766

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

            
783
#[derive(Debug, JetStreamWireFormat)]
784
pub struct Rsymlink {
785
    pub qid: Qid,
786
}
787

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

            
806
#[derive(Debug, JetStreamWireFormat)]
807
pub struct Rmknod {
808
    pub qid: Qid,
809
}
810

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

            
827
/// readlink -- read symlink value
828
///
829
/// ```text
830
/// size[4] Treadlink tag[2] fid[4]
831
/// size[4] Rreadlink tag[2] target[s]
832
/// ```
833
///
834
/// readlink reads the target of the symbolic link represented by fid.
835
#[derive(Debug, JetStreamWireFormat)]
836
pub struct Treadlink {
837
    pub fid: u32,
838
}
839

            
840
#[derive(Debug, JetStreamWireFormat)]
841
pub struct Rreadlink {
842
    pub target: String,
843
}
844

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

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

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

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

            
925
#[derive(Debug, JetStreamWireFormat)]
926
pub struct Rxattrwalk {
927
    pub size: u64,
928
}
929

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

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

            
961
#[derive(Debug, JetStreamWireFormat)]
962
pub struct Rreaddir {
963
    pub data: Data,
964
}
965

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

            
980
/// lock -- acquire or release a POSIX record lock
981
///
982
/// ```text
983
/// size[4] Tlock tag[2] fid[4] type[1] flags[4] start[8] length[8] proc_id[4] client_id[s]
984
/// size[4] Rlock tag[2] status[1]
985
/// ```
986
///
987
/// lock acquires or releases a POSIX record lock on the open file fid.
988
///
989
/// See the Plan 9 manual page for [lock(5)](http://9p.io/magic/man2html/5/lock).
990
#[derive(Debug, JetStreamWireFormat)]
991
pub struct Tlock {
992
    pub fid: u32,
993
    pub type_: u8,
994
    pub flags: u32,
995
    pub start: u64,
996
    pub length: u64,
997
    pub proc_id: u32,
998
    pub client_id: String,
999
}
#[derive(Debug, JetStreamWireFormat)]
pub struct Rlock {
    pub status: u8,
}
/// 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,
}
#[cfg(not(target_arch = "wasm32"))]
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,
}