Pure Erlang implementation of 9p2000 protocol
filesystem fs 9p2000 erlang 9p

Fix bug in decoding read response

This also adds a lot of new property tests for most of 9p messages.

hauleth.dev 0a0a2070 ed7c4d08

verified
+101 -22
+1 -1
src/e9p_msg.erl
··· 160 160 161 161 do_parse(?Tread, <<FID:4/?int, Offset:8/?int, Len:4/?int>>) -> 162 162 {ok, #tread{fid = FID, offset = Offset, len = Len}}; 163 - do_parse(?Rread, <<Count:4/?int, Data:Count/?int>>) -> 163 + do_parse(?Rread, <<Count:4/?int, Data:Count/binary>>) -> 164 164 {ok, #rread{data = Data}}; 165 165 do_parse(?Twrite, <<FID:4/?int, Offset:8/?int, Len:4/?int, Data:Len/binary>>) -> 166 166 {ok, #twrite{fid = FID, offset = Offset, data = Data}};
+100 -21
test/prop_e9p_msg.erl
··· 13 13 Max = 1 bsl (N * 8) - 1, 14 14 integer(Min, Max). 15 15 16 - afid() -> int(2). 16 + fid() -> int(2). 17 17 18 18 bin_str() -> ?LET({Charlist}, {string()}, 19 19 unicode:characters_to_binary(Charlist)). 20 20 21 - prop_can_decode_encoded_tversion() -> 22 - ?FORALL({Version, MPS}, {bin_str(), afid()}, 23 - begin 24 - enc_dec(#tversion{version = Version, max_packet_size = MPS}) 25 - end). 21 + qid_type() -> union([directory, 22 + append, 23 + excl, 24 + device, 25 + auth, 26 + tmp, 27 + symlink, 28 + regular 29 + ]). 30 + 31 + qid() -> 32 + ?LET({Type, Version, Path}, {qid_type(), int(4), int(8)}, 33 + e9p:make_qid(Type, Version, Path)). 34 + qid(Type) -> 35 + ?LET({Version, Path}, {int(4), int(8)}, 36 + e9p:make_qid(Type, Version, Path)). 26 37 27 - prop_can_decode_encoded_rversion() -> 28 - ?FORALL({Version, MPS}, {bin_str(), afid()}, 29 - begin 30 - enc_dec(#rversion{version = Version, max_packet_size = MPS}) 31 - end). 38 + prop_tversion() -> 39 + ?FORALL({Version, MPS}, {bin_str(), int(4)}, 40 + enc_dec(#tversion{version = Version, max_packet_size = MPS})). 41 + prop_rversion() -> 42 + ?FORALL({Version, MPS}, {bin_str(), fid()}, 43 + enc_dec(#rversion{version = Version, max_packet_size = MPS})). 32 44 33 - prop_can_decode_encoded_tauth() -> 34 - ?FORALL({Afid, Uname, Aname}, {afid(), bin_str(), bin_str()}, 35 - begin 36 - enc_dec(#tauth{afid = Afid, uname = Uname, aname = Aname}) 37 - end). 45 + prop_tauth() -> 46 + ?FORALL({Afid, Uname, Aname}, {fid(), bin_str(), bin_str()}, 47 + enc_dec(#tauth{afid = Afid, 48 + uname = Uname, 49 + aname = Aname})). 50 + prop_rauth() -> 51 + ?FORALL({AQID}, {qid()}, 52 + enc_dec(#rauth{aqid = AQID})). 38 53 39 - prop_can_decode_encoded_rerror() -> 54 + prop_rerror() -> 40 55 ?FORALL({Msg}, {bin_str()}, 41 56 begin 42 57 enc_dec(#rerror{msg = Msg}) 43 58 end). 44 59 45 - prop_can_decode_encoded_rstat() -> 46 - ?FORALL({Type, Dev, Mode, Atime, Mtime, Len, Name, Uid, Gid, Muid}, 47 - {int(2), int(2), int(4), int(4), int(4), int(8), bin_str(), bin_str(), 60 + prop_tattach() -> 61 + ?FORALL({FID, AFID, Uname, Aname}, {fid(), fid(), bin_str(), bin_str()}, 62 + enc_dec(#tattach{ 63 + fid = FID, 64 + afid = AFID, 65 + uname = Uname, 66 + aname = Aname 67 + })). 68 + prop_rattach() -> 69 + ?FORALL({QID}, {qid()}, 70 + enc_dec(#rattach{qid = QID})). 71 + 72 + prop_twalk() -> 73 + ?FORALL({FID, NewFID, Names}, {fid(), fid(), list(bin_str())}, 74 + enc_dec(#twalk{fid = FID, new_fid = NewFID, names = Names})). 75 + prop_rwalk() -> 76 + ?FORALL({QIDs}, {list(qid())}, 77 + enc_dec(#rwalk{qids = QIDs})). 78 + 79 + prop_topen() -> 80 + ?FORALL({FID, Mode}, {fid(), int(1)}, 81 + enc_dec(#topen{fid = FID, mode = Mode})). 82 + prop_ropen() -> 83 + ?FORALL({QID, IOUnit}, {qid(), int(4)}, 84 + enc_dec(#ropen{qid = QID, io_unit = IOUnit})). 85 + 86 + prop_tcreate() -> 87 + ?FORALL({FID, Name, Perm, Mode}, {fid(), bin_str(), int(4), int(1)}, 88 + enc_dec(#tcreate{fid = FID, 89 + name = Name, 90 + perm = Perm, 91 + mode = Mode})). 92 + prop_rcreate() -> 93 + ?FORALL({QID, IOUnit}, {qid(), int(4)}, 94 + enc_dec(#rcreate{qid = QID, io_unit = IOUnit})). 95 + 96 + prop_tremove() -> 97 + ?FORALL({FID}, {fid()}, 98 + enc_dec(#tremove{fid = FID})). 99 + 100 + prop_tclunk() -> 101 + ?FORALL({FID}, {fid()}, 102 + enc_dec(#tclunk{fid = FID})). 103 + 104 + prop_tread() -> 105 + ?FORALL({FID, Offset, Len}, {fid(), int(8), int(4)}, 106 + enc_dec(#tread{fid = FID, offset = Offset, len = Len})). 107 + prop_rread() -> 108 + ?FORALL({Data}, {binary()}, 109 + enc_dec(#rread{data = Data})). 110 + 111 + prop_twrite() -> 112 + ?FORALL({FID, Offset, Data}, {fid(), int(8), binary()}, 113 + enc_dec(#twrite{fid = FID, offset = Offset, data = Data})). 114 + prop_rwrite() -> 115 + ?FORALL({Len}, {int(4)}, 116 + enc_dec(#rwrite{len = Len})). 117 + 118 + prop_tstat() -> 119 + ?FORALL({FID}, {fid()}, 120 + enc_dec(#tstat{fid = FID})). 121 + prop_rstat() -> 122 + ?FORALL({QID, Type, Dev, Mode, Atime, Mtime, Len, Name, Uid, Gid, Muid}, 123 + {qid(regular), int(2), int(2), int(4), int(4), int(4), int(8), bin_str(), bin_str(), 48 124 bin_str(), bin_str()}, 49 125 begin 50 126 enc_dec(#rstat{ 51 127 stat = #{ 52 128 type => Type, 53 129 dev => Dev, 54 - qid => e9p:make_qid(directory, 0, 0, []), 130 + qid => QID, 55 131 mode => Mode, 56 132 atime => Atime, 57 133 mtime => Mtime, ··· 62 138 muid => Muid 63 139 }}) 64 140 end). 141 + 142 + prop_tflush() -> 143 + ?FORALL({Tag}, {int(2)}, enc_dec(#tflush{tag = Tag})). 65 144 66 145 enc_dec(Data) -> 67 146 Tag = 1,