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 }