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     //public const int maxPipeSize = 256;
 12     public const int maxPipeSize = numDirectBlockNumbers * blockSize;
 13 
 14     public enum FileType : int
 15     {
 16         free = 0regular = 1directory = 2characterSpecial = 3blockSpecial = 4fifo = 5symlink = 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 flagsFileType fileTypeAccess ownerAccessAccess groupAccessAccess 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 modeINode.Flags& flagsFileType& fileTypeAccess& ownerAccessAccess& groupAccessAccess& 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 inodeNumberint 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 fileSystemIndexint 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& leftconst INodeKey& right)
135     {
136         return left.inodeNumber == right.inodeNumber && left.fsNumber == right.fsNumber;
137     }
138 
139     public class INodeKeyHash : UnaryFun<INodeKeyulong>
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(invalidINodeNumber0))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(modeflagsfileTypeownerAccessgroupAccessotherAccess);
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(flagsfileTypeownerAccessgroupAccessotherAccess);
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(flagsfileTypeownerAccessgroupAccessotherAccess);
292         }
293         public void SetAccessMode(int accessMode)
294         {
295             Flags f;
296             FileType t;
297             DecodeMode(accessModeftownerAccessgroupAccessotherAccess);
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(processeswaitingProcesses);
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(processeswaitingPipeReaders);
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(processeswaitingPipeWriters);
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 indexint 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 uidint gidAccess 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(processTableprocess);
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(processTableprocess);
675                 }
676             }
677         }
678         private INode* inode;
679     }
680 }