1 // Written in the D programming language. 2 3 /** 4 A type for representing the stat object of the 9P / Styx protocol. 5 6 Copyright: LightHouse Software, 2021 7 License: $(HTTP https://github.com/aquaratixc/ESL-License, Experimental Software License 1.0). 8 Authors: Oleg Bakharev, 9 Ilya Pertsev 10 */ 11 module styx2000.protobj.stat; 12 13 private { 14 import std.conv : to; 15 import std.string : format; 16 17 import styx2000.lowlevel.endianness; 18 import styx2000.lowlevel.vls; 19 20 import styx2000.protobj.styxobject; 21 } 22 23 public { 24 import styx2000.protobj.perm; 25 import styx2000.protobj.qid; 26 } 27 28 29 /** 30 A class that provides a type for the stat field in some Styx messages. Inherits methods from the StyxObject class. 31 See_Also: 32 https://web.archive.org/web/20201029184954/https://powerman.name/Inferno/man/5/0intro.html 33 */ 34 class Stat : StyxObject 35 { 36 protected { 37 ushort _type; 38 uint _dev; 39 Qid _qid; 40 Perm _mode; 41 uint _atime; 42 uint _mtime; 43 ulong _length; 44 string _name; 45 string _uid; 46 string _gid; 47 string _muid; 48 49 ubyte[] _representation; 50 } 51 52 private { 53 // update internal byte representation: assume name, uid, gid and muid is setted correctly 54 void updateVLSFields() 55 { 56 // position of first VLS 57 auto vlsPosition = 43; 58 // 4 is position of field named "type" 59 ubyte[] _internals = _representation[4..vlsPosition]; 60 61 _internals ~= VariableLengthSequence.pack(cast(ubyte[]) _name); 62 _internals ~= VariableLengthSequence.pack(cast(ubyte[]) _uid); 63 _internals ~= VariableLengthSequence.pack(cast(ubyte[]) _gid); 64 _internals ~= VariableLengthSequence.pack(cast(ubyte[]) _muid); 65 66 _representation = VariableLengthSequence.pack( 67 VariableLengthSequence.pack(_internals) 68 ); 69 } 70 } 71 72 /** 73 A constructor that creates an object of the Stat class with the given parameters. 74 If called without parameters, then the default parameter for type, dev, atime, mtime, length is zero; 75 default value for Perm and Qid parameter is standard initialized values for their (see Perm and Qid 76 classes); the default parameter for name, uid, gid and muid is empty string. 77 Params: 78 type = Major server version. 79 dev = Minor server version. 80 qid = Unique server id for filesystem object. 81 perm = Permission. 82 atime = Last acess time (in Unix epoch format). 83 mtime = Last modification time (in Unix epoch format). 84 length = Filesystem object size (in bytes). 85 name = Filesystem object name. 86 uid = Owner name. 87 gid = Group of owner name. 88 muid = Name of user, who modified file. 89 90 Typical usage: 91 ---- 92 // chmod 775 (drwxrwxr-x) 93 Perm perm = new Perm; 94 perm.setPerm( 95 STYX_FILE_PERMISSION.DMDIR | STYX_FILE_PERMISSION.OWNER_EXEC | STYX_FILE_PERMISSION.OWNER_READ | STYX_FILE_PERMISSION.OWNER_WRITE | 96 STYX_FILE_PERMISSION.GROUP_READ | STYX_FILE_PERMISSION.GROUP_WRITE | STYX_FILE_PERMISSION.GROUP_EXEC | 97 STYX_FILE_PERMISSION.OTHER_READ | STYX_FILE_PERMISSION.OTHER_EXEC 98 ); 99 100 Stat stat = new Stat( 101 // type and dev for kernel use (taken from some experiments with styxdecoder, see above) 102 77, 4, 103 new Qid, 104 // permissions 105 perm, 106 // access time 107 123456789, 108 // modification time 109 123456, 110 // conventional length for all directories is 0 111 0, 112 // file name (this, directory name) 113 "test", 114 // user name (owner of file) 115 "user", 116 // user group name 117 "users", 118 // others group name 119 "" 120 ); 121 ---- 122 */ 123 this( 124 ushort type = 0, 125 uint dev = 0, 126 Qid qid = new Qid, 127 Perm mode = new Perm, 128 uint atime = 0, 129 uint mtime = 0, 130 ulong length = 0, 131 string name = "", 132 string uid = "", 133 string gid = "", 134 string muid = "" 135 ) 136 { 137 _type = type; 138 _dev = dev; 139 _qid = qid; 140 _mode = mode; 141 _atime = atime; 142 _mtime = mtime; 143 _length = length; 144 _name = name; 145 _uid = uid; 146 _gid = gid; 147 _muid = muid; 148 149 ubyte[] _internals; 150 // type 151 _internals ~= toLEBytes!ushort(type); 152 // dev 153 _internals ~= toLEBytes!uint(dev); 154 // qid 155 _internals ~= qid.pack; 156 // mode 157 _internals ~= mode.pack; 158 // atime 159 _internals ~= toLEBytes!uint(atime); 160 // mtime 161 _internals ~= toLEBytes!uint(mtime); 162 // length 163 _internals ~= toLEBytes!ulong(length); 164 // name 165 _internals ~= VariableLengthSequence.pack(cast(ubyte[]) name); 166 // uid 167 _internals ~= VariableLengthSequence.pack(cast(ubyte[]) uid); 168 // gid 169 _internals ~= VariableLengthSequence.pack(cast(ubyte[]) gid); 170 // muid 171 _internals ~= VariableLengthSequence.pack(cast(ubyte[]) muid); 172 173 // build internal representation 174 _representation = VariableLengthSequence.pack( 175 VariableLengthSequence.pack(_internals) 176 ); 177 } 178 179 /// Set type from unsigned value 180 void setType(ushort type) 181 { 182 _type = type; 183 _representation[4..6] = toLEBytes!ushort(type); 184 } 185 186 /// Set device from unsigned value 187 void setDev(uint dev) 188 { 189 _dev = dev; 190 _representation[6..10] = toLEBytes!uint(dev); 191 } 192 193 /// Set Qid from Qid type 194 void setQid(Qid qid) 195 { 196 _qid = qid; 197 _representation[10..23] = qid.pack; 198 } 199 200 /// Set mode from Perm type 201 void setMode(Perm mode) 202 { 203 _mode = mode; 204 _representation[23..27] = mode.pack; 205 } 206 207 /// Set access time from unsigned value 208 void setAtime(uint atime) 209 { 210 _atime = atime; 211 _representation[27..31] = toLEBytes!uint(atime); 212 } 213 214 /// Set modification time from unsigned value 215 void setMtime(uint mtime) 216 { 217 _mtime = mtime; 218 _representation[31..35] = toLEBytes!uint(mtime); 219 } 220 221 /// Set size (in bytes) from unsigned value 222 void setLength(ulong length) 223 { 224 _length = length; 225 _representation[35..43] = toLEBytes!ulong(length); 226 } 227 228 /// Set name from string 229 void setName(string name) 230 { 231 _name = name; 232 updateVLSFields; 233 } 234 235 /// Set user name from string 236 void setUid(string uid) 237 { 238 _uid = uid; 239 updateVLSFields; 240 } 241 242 /// Set user group name from string 243 void setGid(string gid) 244 { 245 _gid = gid; 246 updateVLSFields; 247 } 248 249 /// Set modificator's name from string 250 void setMuid(string muid) 251 { 252 _muid = muid; 253 updateVLSFields; 254 } 255 256 /// Get type from Stat object 257 ushort getType() 258 { 259 return _type; 260 } 261 262 /// Get device from Stat object 263 uint getDev() 264 { 265 return _dev; 266 } 267 268 /// Get Qid from Stat object 269 Qid getQid() 270 { 271 return _qid; 272 } 273 274 /// Get mode from Stat object 275 Perm getMode() 276 { 277 return _mode; 278 } 279 280 /// Get access time from Stat object 281 uint getAtime() 282 { 283 return _atime; 284 } 285 286 /// Get modification time from Stat object 287 uint getMtime() 288 { 289 return _mtime; 290 } 291 292 /// Get size from Stat object 293 ulong getLength() 294 { 295 return _length; 296 } 297 298 /// Get name from Stat object 299 string getName() 300 { 301 return _name; 302 } 303 304 /// Get user name from Stat object 305 string getUid() 306 { 307 return _uid; 308 } 309 310 /// Get user group name from Stat object 311 string getGid() 312 { 313 return _gid; 314 } 315 316 /// Get modificator's name from Stat object 317 string getMuid() 318 { 319 return _muid; 320 } 321 322 /// Pack to bytes array 323 ubyte[] pack() 324 { 325 return _representation; 326 } 327 328 /// Unpack from bytes array 329 void unpack(ubyte[] bytes...) 330 { 331 _representation = bytes; 332 // unpack all 333 ubyte[] _content = VariableLengthSequence.unpack(VariableLengthSequence.unpack(bytes)); 334 _type = fromLEBytes!ushort(_content[0..2]); 335 _dev = fromLEBytes!uint(_content[2..6]); 336 _qid = new Qid; 337 _qid.unpack(_content[6..19]); 338 _mode = new Perm; 339 _mode.unpack(_content[19..23]); 340 _atime = fromLEBytes!uint(_content[23..27]); 341 _mtime = fromLEBytes!uint(_content[27..31]); 342 _length = fromLEBytes!uint(_content[31..39]); 343 _name = cast(string) VariableLengthSequence.unpack(_content[39..$]); 344 // position for Variable Length Sequences (aka VLS) (name, uid, gid, muid) 345 // 39 - beginning of first VLS, _name.length - size of first VLS, 2 - two bytes is marker of VLS size 346 size_t vlsPosition = 39 + _name.length + 2; 347 _uid = cast(string) VariableLengthSequence.unpack(_content[vlsPosition..$]); 348 // next VLS started on position vlsPosition + size of previous VLS + 2 bytes (size of VLS size marker) 349 vlsPosition += _uid.length + 2; 350 _gid = cast(string) VariableLengthSequence.unpack(_content[vlsPosition..$]); 351 vlsPosition += _gid.length + 2; 352 _muid = cast(string) VariableLengthSequence.unpack(_content[vlsPosition..$]); 353 } 354 355 /// Convenient string representation of an object for printing 356 override string toString() 357 { 358 return format( 359 `Stat(type=%s, dev=%s, qid=%s, mode=%s, atime=%d, mtime=%d, length=%s, name="%s", uid="%s", gid="%s", muid="%s")`, 360 _type.to!string, 361 _dev.to!string, 362 _qid.to!string, 363 _mode.to!string, 364 _atime, 365 _mtime, 366 _length, 367 (_name == "") ? `` : _name, 368 (_uid == "") ? `` : _uid, 369 (_gid == "") ? `` : _gid, 370 (_muid == "") ? `` : _muid 371 ); 372 } 373 374 /// An alias for easier packing into a byte array without having to manually call the pack() method 375 alias pack this; 376 }