1 using System;
2 using System.IO;
3 using System.Collections;
4 using cmsx.util;
5
6 namespace cmsx.kernel
7 {
8 public const int invalidINodeNumber = 0;
9 public const int maxCachedINodes = 1024;
10 public const int numDirectBlockNumbers = 17;
11
12 public const int maxPipeSize = numDirectBlockNumbers * blockSize;
13
14 public enum FileType : int
15 {
16 free = 0, regular = 1, directory = 2, characterSpecial = 3, blockSpecial = 4, fifo = 5, symlink = 6
17 }
18
19 public nothrow string FileTypeStr(FileType fileType)
20 {
21 switch (fileType)
22 {
23 case FileType.free: return "free";
24 case FileType.regular: return "regular";
25 case FileType.directory: return "directory";
26 case FileType.characterSpecial: return "characterSpecial";
27 case FileType.blockSpecial: return "blockSpecial";
28 case FileType.fifo: return "fifo";
29 case FileType.symlink: return "symlink";
30 }
31 return string();
32 }
33
34 public enum Access : int
35 {
36 none = 0,
37 read = 1 << 2,
38 write = 1 << 1,
39 execute = 1 << 0
40 }
41
42 public nothrow string AccessStr(Access access)
43 {
44 string s;
45 if ((access & Access.read) != Access.none)
46 {
47 s.Append("read");
48 }
49 if ((access & Access.write) != Access.none)
50 {
51 if (!s.IsEmpty())
52 {
53 s.Append('-');
54 }
55 s.Append("write");
56 }
57 if ((access & Access.execute) != Access.none)
58 {
59 if (!s.IsEmpty())
60 {
61 s.Append('-');
62 }
63 s.Append("execute");
64 }
65 if (s.IsEmpty())
66 {
67 s.Append("-");
68 }
69 return s;
70 }
71
72 public inline nothrow int EncodeMode(INode.Flags flags, FileType fileType, Access ownerAccess, Access groupAccess, Access otherAccess)
73 {
74 int mntpnt = cast<int>((flags & INode.Flags.mountPoint) != INode.Flags.none);
75 return (mntpnt << 12) | (cast<int>(fileType) << 9) | (cast<int>(ownerAccess) << 6) | (cast<int>(groupAccess) << 3) | (cast<int>(otherAccess));
76 }
77
78 public inline nothrow void DecodeMode(int mode, INode.Flags& flags, FileType& fileType, Access& ownerAccess, Access& groupAccess, Access& otherAccess)
79 {
80 if (((mode >> 12) & 1) != 0)
81 {
82 flags = cast<INode.Flags>(flags | INode.Flags.mountPoint);
83 }
84 else
85 {
86 flags = cast<INode.Flags>(flags & ~INode.Flags.mountPoint);
87 }
88 fileType = cast<FileType>((mode >> 9) & 7);
89 ownerAccess = cast<Access>((mode >> 6) & 7);
90 groupAccess = cast<Access>((mode >> 3) & 7);
91 otherAccess = cast<Access>(mode & 7);
92 }
93
94 public inline nothrow int GetINodeBlockNumber(int inodeNumber, int firstINodeBlockNumber)
95 {
96 return (inodeNumber - 1) / numINodesInBlock + firstINodeBlockNumber;
97 }
98
99 public inline nothrow int GetINodeIndex(int inodeNumber)
100 {
101 return (inodeNumber - 1) % numINodesInBlock;
102 }
103
104 public inline nothrow int GetFileSystemIndex(int fsNumber)
105 {
106 return (fsNumber >> 24) & 0x7F;
107 }
108
109 public inline nothrow int GetHostFileIndex(int fsNumber)
110 {
111 return fsNumber & 0x00FFFFFF;
112 }
113
114 public inline nothrow int MakeFSNumber(int fileSystemIndex, int hostFileIndex)
115 {
116 return ((fileSystemIndex & 0x7F) << 24) | (hostFileIndex & 0x00FFFFFF);
117 }
118
119 public class INodeKey
120 {
121 public nothrow INodeKey(int inodeNumber_, int fsNumber_) : inodeNumber(inodeNumber_), fsNumber(fsNumber_)
122 {
123 }
124 public nothrow string ToString() const
125 {
126 string s;
127 s.Append("inode.").Append(ToString(fsNumber)).Append('.').Append(ToString(inodeNumber));
128 return s;
129 }
130 public int inodeNumber;
131 public int fsNumber;
132 }
133
134 public nothrow bool operator==(const INodeKey& left, const INodeKey& right)
135 {
136 return left.inodeNumber == right.inodeNumber && left.fsNumber == right.fsNumber;
137 }
138
139 public class INodeKeyHash : UnaryFun<INodeKey, ulong>
140 {
141 public inline nothrow ulong operator()(const INodeKey& key) const
142 {
143 return cast<ulong>(1099511628211 * key.fsNumber + key.inodeNumber);
144 }
145 }
146
147 public class INode
148 {
149 public enum Flags : byte
150 {
151 none = 0u,
152 locked = 1u << 0u,
153 dirty = 1u << 1u,
154 mountPoint = 1u << 2u,
155 pipeFull = 1u << 3u,
156 pipeEmpty = 1u << 4u
157 }
158 public nothrow string FlagStr(Flags flags)
159 {
160 string s = "flags";
161 if ((flags & Flags.locked) != Flags.none)
162 {
163 s.Append(".locked");
164 }
165 if ((flags & Flags.dirty) != Flags.none)
166 {
167 s.Append(".dirty");
168 }
169 if ((flags & Flags.mountPoint) != Flags.none)
170 {
171 s.Append(".mountPoint");
172 }
173 return s;
174 }
175 public nothrow INode(INodeManager* manager_) : manager(manager_), key(INodeKey(invalidINodeNumber, 0)), flags(Flags.none), useCount(0), iterator(),
176 mode(0), uid(-1), gid(-1), fileSize(0), ctime(), mtime(), atime(), nlinks(1u),
177 singleIndirectBlockNumber(invalidBlockNumber), doubleIndirectBlockNumber(invalidBlockNumber), tripleIndirectBlockNumber(invalidBlockNumber), owner(null)
178 {
179 long n = directBlockNumbers.Length();
180 for (long i = 0; i < n; ++i;)
181 {
182 directBlockNumbers[i] = invalidBlockNumber;
183 }
184 }
185 public inline nothrow Process* Owner() const
186 {
187 return owner;
188 }
189 public inline nothrow void SetOwner(Process* owner_)
190 {
191 owner = owner_;
192 }
193 public inline nothrow void ResetOwner()
194 {
195 owner = null;
196 }
197 public nothrow string ToString() const
198 {
199 string s;
200 s.Append(key.ToString()).Append('.').Append(FlagStr(flags)).Append(".count=").Append(ToString(useCount)).Append(".nlinks=").Append(ToString(nlinks));
201 return s;
202 }
203 public inline nothrow const INodeKey& Key() const
204 {
205 return key;
206 }
207 public nothrow void SetKey(const INodeKey& key_)
208 {
209 key = key_;
210 }
211 public inline nothrow bool GetFlag(Flags flag) const
212 {
213 return (flags & flag) != Flags.none;
214 }
215 public inline nothrow void SetFlag(Flags flag)
216 {
217 flags = cast<Flags>(flags | flag);
218 }
219 public inline nothrow void ResetFlag(Flags flag)
220 {
221 flags = cast<Flags>(flags & ~flag);
222 }
223 public inline nothrow void ResetFlags()
224 {
225 flags = Flags.none;
226 }
227 public inline nothrow int GetUseCount() const
228 {
229 return useCount;
230 }
231 public inline nothrow void SetUseCount(int useCount_)
232 {
233 useCount = useCount_;
234 }
235 public void Read(MemoryReader& reader)
236 {
237 mode = reader.ReadInt();
238 DecodeMode(mode, flags, fileType, ownerAccess, groupAccess, otherAccess);
239 uid = reader.ReadInt();
240 gid = reader.ReadInt();
241 fileSize = reader.ReadLong();
242 ctime = reader.ReadDateTime();
243 mtime = reader.ReadDateTime();
244 atime = reader.ReadDateTime();
245 nlinks = reader.ReadInt();
246 long n = directBlockNumbers.Length();
247 for (long i = 0; i < n; ++i;)
248 {
249 directBlockNumbers[i] = reader.ReadInt();
250 }
251 singleIndirectBlockNumber = reader.ReadInt();
252 doubleIndirectBlockNumber = reader.ReadInt();
253 tripleIndirectBlockNumber = reader.ReadInt();
254 }
255 public void Write(MemoryWriter& writer)
256 {
257 mode = EncodeMode(flags, fileType, ownerAccess, groupAccess, otherAccess);
258 writer.Write(mode);
259 writer.Write(uid);
260 writer.Write(gid);
261 writer.Write(fileSize);
262 writer.Write(ctime);
263 writer.Write(mtime);
264 writer.Write(atime);
265 writer.Write(nlinks);
266 long n = directBlockNumbers.Length();
267 for (long i = 0; i < n; ++i;)
268 {
269 writer.Write(directBlockNumbers[i]);
270 }
271 writer.Write(singleIndirectBlockNumber);
272 writer.Write(doubleIndirectBlockNumber);
273 writer.Write(tripleIndirectBlockNumber);
274 }
275 public inline nothrow FileType Type() const
276 {
277 return fileType;
278 }
279 public inline nothrow void SetType(FileType fileType_)
280 {
281 fileType = fileType_;
282 SetCTime();
283 SetFlag(Flags.dirty);
284 }
285 public inline nothrow int Mode() const
286 {
287 return mode;
288 }
289 public nothrow void SetMode()
290 {
291 mode = EncodeMode(flags, fileType, ownerAccess, groupAccess, otherAccess);
292 }
293 public void SetAccessMode(int accessMode)
294 {
295 Flags f;
296 FileType t;
297 DecodeMode(accessMode, f, t, ownerAccess, groupAccess, otherAccess);
298 SetCTime();
299 SetFlag(Flags.dirty);
300 }
301 public inline nothrow int UID() const
302 {
303 return uid;
304 }
305 public inline nothrow void SetUID(int uid_)
306 {
307 uid = uid_;
308 SetCTime();
309 SetFlag(Flags.dirty);
310 }
311 public inline nothrow int GID() const
312 {
313 return gid;
314 }
315 public inline nothrow void SetGID(int gid_)
316 {
317 gid = gid_;
318 SetCTime();
319 SetFlag(Flags.dirty);
320 }
321 public inline nothrow Access OwnerAccess() const
322 {
323 return ownerAccess;
324 }
325 public inline nothrow void SetOwnerAccess(Access ownerAccess_)
326 {
327 ownerAccess = ownerAccess_;
328 SetCTime();
329 SetFlag(Flags.dirty);
330 }
331 public inline nothrow Access GroupAccess() const
332 {
333 return groupAccess;
334 }
335 public inline nothrow void SetGroupAccess(Access groupAccess_)
336 {
337 groupAccess = groupAccess_;
338 SetCTime();
339 SetFlag(Flags.dirty);
340 }
341 public inline nothrow Access OtherAccess() const
342 {
343 return otherAccess;
344 }
345 public inline nothrow void SetOtherAccess(Access otherAccess_)
346 {
347 otherAccess = otherAccess_;
348 SetCTime();
349 SetFlag(Flags.dirty);
350 }
351 public inline nothrow const DateTime& CTime() const
352 {
353 return ctime;
354 }
355 public nothrow void SetCTime()
356 {
357 ctime = GetCurrentDateTime();
358 SetFlag(Flags.dirty);
359 }
360 public nothrow void SetCTime(const DateTime& ctime_)
361 {
362 ctime = ctime_;
363 SetFlag(Flags.dirty);
364 }
365 public inline nothrow const DateTime& MTime() const
366 {
367 return mtime;
368 }
369 public nothrow void SetMTime()
370 {
371 mtime = GetCurrentDateTime();
372 SetFlag(Flags.dirty);
373 }
374 public nothrow void SetMTime(const DateTime& mtime_)
375 {
376 mtime = mtime_;
377 SetFlag(Flags.dirty);
378 }
379 public inline nothrow const DateTime& ATime() const
380 {
381 return atime;
382 }
383 public nothrow void SetATime()
384 {
385 atime = GetCurrentDateTime();
386 SetFlag(Flags.dirty);
387 }
388 public nothrow void SetATime(const DateTime& atime_)
389 {
390 atime = atime_;
391 SetFlag(Flags.dirty);
392 }
393 public inline nothrow int GetNumLinks() const
394 {
395 return nlinks;
396 }
397 public inline nothrow void SetNumLinks(int nlinks_)
398 {
399 nlinks = nlinks_;
400 SetCTime();
401 SetFlag(Flags.dirty);
402 }
403 public nothrow void AddWaitingProcess(Process* process)
404 {
405 waitingProcesses.Add(process);
406 }
407 public nothrow List<Process*> GetWaitingProcesses()
408 {
409 List<Process*> processes;
410 Swap(processes, waitingProcesses);
411 return processes;
412 }
413 public nothrow void AddWaitingPipeReader(Process* reader)
414 {
415 waitingPipeReaders.Add(reader);
416 }
417 public nothrow List<Process*> GetWaitingPipeReaders()
418 {
419 List<Process*> processes;
420 Swap(processes, waitingPipeReaders);
421 return processes;
422 }
423 public nothrow void AddWaitingPipeWriter(Process* writer)
424 {
425 waitingPipeWriters.Add(writer);
426 }
427 public nothrow List<Process*> GetWaitingPipeWriters()
428 {
429 List<Process*> processes;
430 Swap(processes, waitingPipeWriters);
431 return processes;
432 }
433 public nothrow LinkedList<INode*>.Iterator GetIterator() const
434 {
435 return iterator;
436 }
437 public nothrow void SetIterator(LinkedList<INode*>.Iterator iterator_)
438 {
439 iterator = iterator_;
440 }
441 public inline nothrow int GetDirectBlockNumber(int index) const
442 {
443 #assert(index >= 0 && index < numDirectBlockNumbers);
444 return directBlockNumbers[index];
445 }
446 public inline nothrow void SetDirectBlockNumber(int index, int blockNumber)
447 {
448 directBlockNumbers[index] = blockNumber;
449 SetFlag(Flags.dirty);
450 }
451 public inline nothrow int GetSingleIndirectBlockNumber() const
452 {
453 return singleIndirectBlockNumber;
454 }
455 public inline nothrow void SetSingleIndirectBlockNumber(int singleIndirectBlockNumber_)
456 {
457 singleIndirectBlockNumber = singleIndirectBlockNumber_;
458 SetFlag(Flags.dirty);
459 }
460 public inline nothrow int GetDoubleIndirectBlockNumber() const
461 {
462 return doubleIndirectBlockNumber;
463 }
464 public inline nothrow void SetDoubleIndirectBlockNumber(int doubleIndirectBlockNumber_)
465 {
466 doubleIndirectBlockNumber = doubleIndirectBlockNumber_;
467 SetFlag(Flags.dirty);
468 }
469 public inline nothrow int GetTripleIndirectBlockNumber() const
470 {
471 return tripleIndirectBlockNumber;
472 }
473 public inline nothrow void SetTripleIndirectBlockNumber(int tripleIndirectBlockNumber_)
474 {
475 tripleIndirectBlockNumber = tripleIndirectBlockNumber_;
476 SetFlag(Flags.dirty);
477 }
478 public inline nothrow long GetFileSize() const
479 {
480 return fileSize;
481 }
482 public inline nothrow void SetFileSize(long fileSize_)
483 {
484 fileSize = fileSize_;
485 SetCTime();
486 SetFlag(Flags.dirty);
487 }
488 public inline nothrow int GetNumBlocks() const
489 {
490 if (fileSize == 0)
491 {
492 return 0;
493 }
494 else
495 {
496 return cast<int>((fileSize - 1) / blockSize + 1);
497 }
498 }
499 public void CheckPermissions(int uid, int gid, Access access)
500 {
501 if (this->uid == uid)
502 {
503 if ((access & ownerAccess) == access)
504 {
505 return;
506 }
507 else
508 {
509 throw SystemError(EPERM, "no " + AccessStr(access) + " access");
510 }
511 }
512 if (this->gid == gid)
513 {
514 if ((access & groupAccess) == access)
515 {
516 return;
517 }
518 else
519 {
520 throw SystemError(EPERM, "no " + AccessStr(access) + " access");
521 }
522 }
523 if ((access & otherAccess) == access)
524 {
525 return;
526 }
527 else
528 {
529 throw SystemError(EPERM, "no " + AccessStr(access) + " access");
530 }
531 }
532 public nothrow void Clear()
533 {
534 ResetFlags();
535 useCount = 1;
536 mode = 0;
537 uid = -1;
538 gid = -1;
539 fileSize = 0;
540 ctime = DateTime();
541 mtime = DateTime();
542 atime = DateTime();
543 nlinks = 0;
544 long n = directBlockNumbers.Length();
545 for (long i = 0; i < n; ++i;)
546 {
547 directBlockNumbers[i] = 0;
548 }
549 singleIndirectBlockNumber = 0;
550 doubleIndirectBlockNumber = 0;
551 tripleIndirectBlockNumber = 0;
552 fileType = FileType.free;
553 ownerAccess = Access.none;
554 groupAccess = Access.none;
555 otherAccess = Access.none;
556 }
557 public inline nothrow INodeManager* Manager()
558 {
559 return manager;
560 }
561 public inline nothrow long ReadPos() const
562 {
563 return readPos;
564 }
565 public inline nothrow long WritePos() const
566 {
567 return writePos;
568 }
569 public inline nothrow void SetReadPos(long readPos_)
570 {
571 readPos = readPos_;
572 }
573 public inline nothrow void SetWritePos(long writePos_)
574 {
575 writePos = writePos_;
576 }
577 private INodeKey key;
578 private Flags flags;
579 private int useCount;
580 private List<Process*> waitingProcesses;
581 private List<Process*> waitingPipeReaders;
582 private List<Process*> waitingPipeWriters;
583 private LinkedList<INode*>.Iterator iterator;
584 private int mode;
585 private int uid;
586 private int gid;
587 private long fileSize;
588 private DateTime ctime;
589 private DateTime mtime;
590 private DateTime atime;
591 private int nlinks;
592 private int[numDirectBlockNumbers] directBlockNumbers;
593 private int singleIndirectBlockNumber;
594 private int doubleIndirectBlockNumber;
595 private int tripleIndirectBlockNumber;
596 private FileType fileType;
597 private Access ownerAccess;
598 private Access groupAccess;
599 private Access otherAccess;
600 private INodeManager* manager;
601 private Process* owner;
602 private long readPos;
603 private long writePos;
604 }
605
606 public class INodePutter
607 {
608 public nothrow INodePutter() : inode(null)
609 {
610 }
611 public nothrow INodePutter(INode* inode_) : inode(inode_)
612 {
613 }
614 public inline nothrow void ResetINode()
615 {
616 inode = null;
617 }
618 public nothrow void ResetINode(INode* newINode)
619 {
620 if (inode != newINode)
621 {
622 if (inode != null)
623 {
624 inode->Manager()->PutINode(inode);
625 }
626 inode = newINode;
627 }
628 }
629 public ~INodePutter()
630 {
631 if (inode != null)
632 {
633 inode->Manager()->PutINode(inode);
634 }
635 }
636 private SuperBlock* sb;
637 private INode* inode;
638 }
639
640 public class INodeLock
641 {
642 public nothrow INodeLock() : inode(null)
643 {
644 }
645 public nothrow INodeLock(INode* inode_) : inode(inode_)
646 {
647 inode->SetFlag(INode.Flags.locked);
648 }
649 public nothrow void Reset(INode* inode_)
650 {
651 if (inode != null)
652 {
653 inode->ResetFlag(INode.Flags.locked);
654 Kernel& kernel = GetKernel();
655 ProcessTable& processTable = kernel.GetProcessTable();
656 List<Process*> waitingProcesses = inode->GetWaitingProcesses();
657 for (Process* process : waitingProcesses)
658 {
659 WakeUpProcess(processTable, process);
660 }
661 }
662 inode = inode_;
663 }
664 public ~INodeLock()
665 {
666 if (inode != null)
667 {
668 inode->ResetFlag(INode.Flags.locked);
669 Kernel& kernel = GetKernel();
670 ProcessTable& processTable = kernel.GetProcessTable();
671 List<Process*> waitingProcesses = inode->GetWaitingProcesses();
672 for (Process* process : waitingProcesses)
673 {
674 WakeUpProcess(processTable, process);
675 }
676 }
677 }
678 private INode* inode;
679 }
680 }