1 using System;
  2 using System.IO;
  3 using System.Collections;
  4 using cmsx.util;
  5 using cmsx.machine;
  6 
  7 namespace cmsx.kernel
  8 {
  9     public const int rootFSMaxFiles = 1024;
 10     public const int rootFSMaxBlocks = 256 * 1024;
 11 
 12     public class RootFileSystem : FileSystem
 13     {
 14         public RootFileSystem(int index_) : base("root"index_false)hostFile(null)
 15         {
 16         }
 17         public override nothrow bool IsRootFileSystem() const
 18         {
 19             return true;
 20         }
 21         public override void Init()
 22         {
 23             if (Log())
 24             {
 25                 LogMessage("fs.root""init");
 26             }
 27             string cmajorRootDir = RtGetEnvironmentVariable("CMAJOR_ROOT");
 28             if (cmajorRootDir.IsEmpty())
 29             {
 30                 throw Exception("CMAJOR_ROOT environment variable not set. Please set it to contain /path/to/cmajor directory");
 31             }
 32             string fsDirPath = GetFullPath(Path.Combine(Path.Combine(Path.Combine(cmajorRootDir"projects")"cmsx")"fs"));
 33             Directory.CreateDirectories(fsDirPath);
 34             hostFilePath = GetFullPath(Path.Combine(fsDirPath"rootfs"));
 35             bool create = false;
 36             if (!System.IO.File.Exists(hostFilePath))
 37             {
 38                 create = true;
 39             }
 40             DiskDriver& diskDriver = GetDiskDriver();
 41             hostFile = diskDriver.GetOrInsertHostFile(hostFilePathtrue);
 42             if (create)
 43             {
 44                 CreateRootFs(rootFSMaxFilesrootFSMaxBlocks);
 45             }
 46             if (blockBitmap.IsNull())
 47             {
 48                 blockBitmap.Reset(new BlockBitmap(0));
 49             }
 50             if (inodeBitmap.IsNull())
 51             {
 52                 inodeBitmap.Reset(new INodeBitmap(0));
 53             }
 54             INode* mntINode = inodeManager.PathToINode(null"/mnt");
 55             if (mntINode == null)
 56             {
 57                 MakeDirectory(null"/mnt"cast<int>(ParseOctal("755")));
 58             }
 59             else
 60             {
 61                 INodePutter putter(mntINode);
 62             }
 63         }
 64         public override int OpenDirectory(Process* processconst string& pathINode* dirINodeINodePutter& inodePutter)
 65         {
 66             int fd = process->fileTable.GetEmptyFileSlot();
 67             process->fileTable.SetFile(fdnew DirectoryFile(dirINode));
 68             inodePutter.ResetINode();
 69             dirINode->ResetFlag(INode.Flags.locked);
 70             return fd;
 71         }
 72         public override int ReadDirectory(Process* processDirectoryFile* dirFileulong inodeNumberAddressulong entryNameAddress)
 73         {
 74             INode* dirINode = dirFile->DirINode();
 75             if (Log())
 76             {
 77                 LogMessage("fs.root.readdirectory"dirINode->ToString());
 78             }
 79             while (dirINode->GetFlag(INode.Flags.locked))
 80             {
 81                 dirINode->AddWaitingProcess(process);
 82                 SleepProcess(processinodeUnlockedEventcast<ulong>(cast<void*>(dirINode))0u);
 83             }
 84             {
 85                 INodeLock lock(dirINode);
 86                 while (dirFile->Offset() < dirINode->GetFileSize())
 87                 {
 88                     int blockNumber = 0;
 89                     int blockOffset = 0;
 90                     blockManager.GetBlockNumber(dirINodedirFile->Offset()blockNumberblockOffsetfalse);
 91                     if (blockNumber == 0)
 92                     {
 93                         return 0;
 94                     }
 95                     Block* block = blockManager.ReadBlock(BlockKey(blockNumberdirINode->Key().fsNumber)null);
 96                     BlockPutter putter(block);
 97                     DirectoryBlock* directoryBlock = cast<DirectoryBlock*>(block);
 98                     for (int index = blockOffset / directoryEntrySize; index < numDirectoryEntriesInBlock && dirFile->Offset() < dirINode->GetFileSize(); ++index;)
 99                     {
100                         DirectoryEntry directoryEntry = directoryBlock->GetDirectoryEntry(index);
101                         if (directoryEntry.inodeNumber == 0)
102                         {
103                             dirFile->SetOffset(dirFile->Offset() + directoryEntrySize);
104                         }
105                         else
106                         {
107                             WriteProcessMemory(GetMachine()processinodeNumberAddresscast<ulong>(directoryEntry.inodeNumber)4uProtection.write);
108                             WriteProcessMemory(GetMachine()processentryNameAddresscast<byte*>(cast<void*>(directoryEntry.name.Chars()))cast<ulong>(directoryEntry.name.Length() + 1)Protection.write);
109                             dirFile->SetOffset(dirFile->Offset() + directoryEntrySize);
110                             return 1;
111                         }
112                     }
113                 }
114             }
115             return 0;
116         }
117         public override void ChangeMode(Process* processconst string& pathINode* inodeint mode)
118         {
119             if (process->uid != inode->UID())
120             {
121                 throw SystemError(EPERM"error changing mode of '" + path + "': user id of the process (" + ToString(process->uid) + ") does not match the owner (" + ToString(inode->UID()) + ") of the file");
122             }
123             inode->SetAccessMode(mode);
124         }
125         public override void ChangeOwner(Process* processconst string& pathINode* inodeint uidint gid)
126         {
127             if (process->uid != 0)
128             {
129                 throw SystemError(EPERM"error changing owner of '" + path + "': not authorized");
130             }
131             inode->SetUID(uid);
132             inode->SetGID(gid);
133         }
134         public override void UpdateFileTimes(Process* processconst string& pathINode* inodeconst DateTime& atimeconst DateTime& mtime)
135         {
136             if (process->uid != inode->UID())
137             {
138                 try
139                 {
140                     if (atime != DateTime() || mtime != DateTime())
141                     {
142                         throw SystemError(EPERM"access time or modification time not default and not owner of the file");
143                     }
144                     inode->CheckPermissions(process->uidprocess->gidAccess.write);
145                 }
146                 catch (const Exception& ex)
147                 {
148                     throw Exception("cannot change file '" + path + "' timestamps: " + ex.Message());
149                 }
150             }
151             if (atime == DateTime())
152             {
153                 inode->SetATime();
154             }
155             else
156             {
157                 inode->SetATime(atime);
158             }
159             if (mtime == DateTime())
160             {
161                 inode->SetMTime();
162             }
163             else
164             {
165                 inode->SetMTime(mtime);
166             }
167         }
168         public override int AllocateBlockNumber()
169         {
170             return blockBitmap->AllocateBlockNumber();
171         }
172         public override void SetBlockFree(int blockNumber)
173         {
174             blockBitmap->SetBlockFree(blockNumber);
175         }
176         public override int GetFreeINodeNumber()
177         {
178             return inodeBitmap->GetFreeINodeNumber();
179         }
180         public override void SetFreeINodeNumber(int inodeNumber)
181         {
182             inodeBitmap->SetFreeINodeNumber(inodeNumber);
183         }
184         public override int GetFirstINodeBlockNumber() const
185         {
186             Block* block = blockManager.ReadBlock(BlockKey(00)null);
187             BlockPutter putter(block);
188             SuperBlock* superBlock = cast<SuperBlock*>(block);
189             return superBlock->GetFirstINodeBlockNumber();
190         }
191         public override INodeKey GetRootDirINodeKey() const
192         {
193             Block* block = blockManager.ReadBlock(BlockKey(00)null);
194             BlockPutter putter(block);
195             SuperBlock* superBlock = cast<SuperBlock*>(block);
196             return INodeKey(superBlock->GetRootDirINodeNumber()0);
197         }
198         public override HostFile* GetHostFile(int fsNumber) const
199         {
200             int hostFileIndex = GetHostFileIndex(fsNumber);
201             if (hostFileIndex != 0)
202             {
203                 throw SystemError(EINVAL"invalid file system number");
204             }
205             return hostFile;
206         }
207         public override int LastBlockNumber() const
208         {
209             Block* block = blockManager.ReadBlock(BlockKey(00)null);
210             BlockPutter putter(block);
211             SuperBlock* superBlock = cast<SuperBlock*>(block);
212             return superBlock->GetLastBlockNumber();
213         }
214         public override void SetLastBlockNumber(int blockNumberSuperBlock* sb)
215         {
216             if (sb != null && sb->Key().fsNumber == 0)
217             {
218                 if (sb->GetLastBlockNumber() < blockNumber)
219                 {
220                     sb->SetLastBlockNumber(blockNumber);
221                 }
222             }
223             else
224             {
225                 Block* block = blockManager.ReadBlock(BlockKey(00)null);
226                 BlockPutter putter(block);
227                 SuperBlock* superBlock = cast<SuperBlock*>(block);
228                 if (superBlock->GetLastBlockNumber() < blockNumber)
229                 {
230                     superBlock->SetLastBlockNumber(blockNumber);
231                 }
232             }
233         }
234         private void CreateRootFs(int maxFilesint maxBlocks)
235         {
236             try
237             {
238                 int numINodeBitmapBlocks = (maxFiles - 1) / (8 * blockSize) + 1;
239                 int numBlockBitmapBlocks = (maxBlocks - 1) / (8 * blockSize) + 1;
240                 int numINodeBlocks = (maxFiles - 1) / numINodesInBlock + 1;
241                 {
242                     Block* block = blockManager.GetBlock(BlockKey(00)null);
243                     block->Clear();
244                     BlockPutter putter(block);
245                     SuperBlock* superBlock = cast<SuperBlock*>(block);
246                     superBlock->SetLastBlockNumber(-1);
247                     superBlock->SetFirstINodeBitmapBlockNumber(1);
248                     superBlock->SetNumINodeBitmapBlocks(numINodeBitmapBlocks);
249                     superBlock->SetFirstBlockBitmapBlockNumber(superBlock->GetFirstINodeBitmapBlockNumber() + superBlock->GetNumINodeBitmapBlocks());
250                     superBlock->SetNumBlockBitmapBlocks(numBlockBitmapBlocks);
251                     superBlock->SetFirstINodeBlockNumber(superBlock->GetFirstBlockBitmapBlockNumber() + superBlock->GetNumBlockBitmapBlocks());
252                     superBlock->SetNumINodeBlocks(numINodeBlocks);
253                     superBlock->SetFirstDataBlockNumber(superBlock->GetFirstINodeBlockNumber() + superBlock->GetNumINodeBlocks());
254                     blockManager.WriteBlock(blocksuperBlock);
255                     superBlock->SetFlag(Block.Flags.valid);
256                 }
257                 blockBitmap.Reset(new BlockBitmap(0));
258                 inodeBitmap.Reset(new INodeBitmap(0));
259                 int rootDirINodeNumber = GetFreeINodeNumber();
260                 {
261                     Block* block = blockManager.ReadBlock(BlockKey(00)null);
262                     BlockPutter putter(block);
263                     SuperBlock* superBlock = cast<SuperBlock*>(block);
264                     superBlock->SetRootDirINodeNumber(rootDirINodeNumber);
265                     blockManager.WriteBlock(blocksuperBlock);
266                 }
267                 blockManager.Flush();
268                 FileSystem* fs = GetMountTable().GetFileSystem(0);
269                 fs->MakeDirectory(null"/"cast<int>(ParseOctal("755")));
270                 blockManager.Flush();
271             }
272             catch (const Exception& ex)
273             {
274                 GetDiskDriver().Stop();
275                 GetConsoleDriver().Stop();
276                 throw;
277             }
278         }
279         public override nothrow bool HasMountDirKey(const INodeKey& mountDirKey) const
280         {
281             return false;
282         }
283         public override nothrow BlockManager* GetBlockManager()
284         {
285             return &blockManager;
286         }
287         public override nothrow INodeManager* GetINodeManager()
288         {
289             return &inodeManager;
290         }
291         private UniquePtr<BlockBitmap> blockBitmap;
292         private UniquePtr<INodeBitmap> inodeBitmap;
293         private string hostFilePath;
294         private HostFile* hostFile;
295         private RootBlockManager blockManager;
296         private RootINodeManager inodeManager;
297     }
298 }