1 using System;
  2 using System.IO;
  3 using System.Collections;
  4 using cmsx.util;
  5 
  6 namespace cmsx.kernel
  7 {
  8     public class INodeBitmap
  9     {
 10         public INodeBitmap(int fsNumber_) : fsNumber(fsNumber_)
 11         {
 12             FileSystem* fs = GetMountTable().GetFileSystem(fsNumber);
 13             Block* sb = fs->GetBlockManager()->ReadBlock(BlockKey(0fsNumber)null);
 14             BlockPutter superBlockPutter(sb);
 15             SuperBlock* superBlock = cast<SuperBlock*>(sb);
 16             int firstNumber = superBlock->GetFirstINodeBitmapBlockNumber();
 17             int bitmapBlockIndex = 0;
 18             Block* block = null;
 19             if (Log())
 20             {
 21                 LogMessage("fs.ibm.init"ToString(firstNumber + bitmapBlockIndex));
 22             }
 23             if (superBlock->GetLastBlockNumber() < firstNumber + bitmapBlockIndex)
 24             {
 25                 block = fs->GetBlockManager()->GetBlock(BlockKey(firstNumber + bitmapBlockIndexsuperBlock->Key().fsNumber)superBlock);
 26                 block->Clear();
 27             }
 28             else
 29             {
 30                 block = fs->GetBlockManager()->ReadBlock(BlockKey(firstNumber + bitmapBlockIndexsuperBlock->Key().fsNumber)superBlock);
 31             }
 32             BlockPutter putter(block);
 33             BitmapBlock* bitmapBlock = cast<BitmapBlock*>(block);
 34             bitmapBlock->SetBit(0);
 35             fs->GetBlockManager()->WriteBlock(blocksuperBlock);
 36         }
 37         public int GetFreeINodeNumber()
 38         {
 39             if (Log())
 40             {
 41                 LogMessage("fs.ibm.getfreeinodenumber""begin");
 42             }
 43             FileSystem* fs = GetMountTable().GetFileSystem(fsNumber);
 44             Block* sb = fs->GetBlockManager()->ReadBlock(BlockKey(0fsNumber)null);
 45             BlockPutter superBlockPutter(sb);
 46             SuperBlock* superBlock = cast<SuperBlock*>(sb);
 47             int firstNumber = superBlock->GetFirstINodeBitmapBlockNumber();
 48             int n = superBlock->GetNumINodeBitmapBlocks();
 49             for (int i = 0; i < n; ++i;)
 50             {
 51                 Block* block = null;
 52                 if (superBlock->GetLastBlockNumber() < firstNumber + i)
 53                 {
 54                     block = fs->GetBlockManager()->GetBlock(BlockKey(firstNumber + isuperBlock->Key().fsNumber)superBlock);
 55                     block->Clear();
 56                 }
 57                 else
 58                 {
 59                     block = fs->GetBlockManager()->ReadBlock(BlockKey(firstNumber + isuperBlock->Key().fsNumber)superBlock);
 60                 }
 61                 BlockPutter putter(block);
 62                 BitmapBlock* bitmapBlock = cast<BitmapBlock*>(block);
 63                 int index = bitmapBlock->GetFirstZeroBitIndex();
 64                 if (index != -1)
 65                 {
 66                     bitmapBlock->SetBit(index);
 67                     int inodeNumber = numBitsInBitmapBlock * i + index;
 68                     if (Log())
 69                     {
 70                         LogMessage("fs.ibm.getfreeinodenumber""end.inode=" + ToString(inodeNumber));
 71                     }
 72                     fs->GetBlockManager()->WriteBlock(blocksuperBlock);
 73                     return inodeNumber;
 74                 }
 75             }
 76             throw SystemError(ERLIMITEXCEEDED"no free inodes");
 77         }
 78         public void SetFreeINodeNumber(int inodeNumber)
 79         {
 80             if (Log())
 81             {
 82                 LogMessage("fs.ibm.setfreeinodenumber""begin.inode=" + ToString(inodeNumber));
 83             }
 84             FileSystem* fs = GetMountTable().GetFileSystem(fsNumber);
 85             Block* sb = fs->GetBlockManager()->ReadBlock(BlockKey(0fsNumber)null);
 86             BlockPutter superBlockPutter(sb);
 87             SuperBlock* superBlock = cast<SuperBlock*>(sb);
 88             int blockNumber = inodeNumber / numBitsInBitmapBlock;
 89             int index = inodeNumber % numBitsInBitmapBlock;
 90             int firstNumber = superBlock->GetFirstINodeBitmapBlockNumber();
 91             Block* block = null;
 92             if (superBlock->GetLastBlockNumber() < firstNumber + blockNumber)
 93             {
 94                 block = fs->GetBlockManager()->GetBlock(BlockKey(firstNumber + blockNumbersuperBlock->Key().fsNumber)superBlock);
 95                 block->Clear();
 96             }
 97             else
 98             {
 99                 block = fs->GetBlockManager()->ReadBlock(BlockKey(firstNumber + blockNumbersuperBlock->Key().fsNumber)superBlock);
100             }
101             {
102                 BlockPutter putter(block);
103                 BitmapBlock* bitmapBlock = cast<BitmapBlock*>(block);
104                 bitmapBlock->ResetBit(index);
105                 fs->GetBlockManager()->WriteBlock(blocksuperBlock);
106             }
107             if (Log())
108             {
109                 LogMessage("fs.ibm.setfreeinodenumber""end.inode=" + ToString(inodeNumber));
110             }
111         }
112         private int fsNumber;
113     }
114 
115     public class RootINodeManager : INodeManager
116     {
117         public RootINodeManager()
118         {
119             for (long i = 0; i < maxCachedINodes; ++i;)
120             {
121                 INode* inode = new INode(this);
122                 inodes.Add(UniquePtr<INode>(inode));
123                 freeINodeList.Add(inode);
124                 inode->SetIterator(LinkedList<INode*>.Iterator(&freeINodeListfreeINodeList.Tail()));
125             }
126         }
127         public override nothrow string Name() const
128         {
129             return "fs.root.imgr";
130         }
131         public override INode* GetINode(const INodeKey& key)
132         {
133             if (Log())
134             {
135                 LogMessage("fs.root.imgr.getinode.begin"key.ToString());
136             }
137             FileSystem* fs = GetMountTable().GetFileSystem(0);
138             while (true)
139             {
140                 HashMap<INodeKeyINode*INodeKeyHash>.ConstIterator it = inodeMap.CFind(key);
141                 if (it != inodeMap.CEnd())
142                 {
143                     INode* inode = it->second;
144                     if (inode->GetFlag(INode.Flags.locked))
145                     {
146                         void* fiberData = OsGetFiberData();
147                         Process* process = cast<Process*>(fiberData);
148                         if (inode->Owner() != process)
149                         {
150                             inode->AddWaitingProcess(process);
151                             SleepProcess(processinodeUnlockedEventcast<ulong>(cast<void*>(inode))0u);
152                             continue;
153                         }
154                         else
155                         {
156                             inode->SetUseCount(inode->GetUseCount() + 1);
157                             if (Log())
158                             {
159                                 LogMessage("fs.root.imgr.getinode.end"inode->ToString());
160                             }
161                             return inode;
162                         }
163                     }
164                     else
165                     {
166                         inode->SetFlag(INode.Flags.locked);
167                         void* fiberData = OsGetFiberData();
168                         Process* process = cast<Process*>(fiberData);
169                         inode->SetOwner(process);
170                         RemoveINodeFromFreeList(inode);
171                         inode->SetUseCount(inode->GetUseCount() + 1);
172                         if (Log())
173                         {
174                             LogMessage("fs.root.imgr.getinode.end"inode->ToString());
175                         }
176                         return inode;
177                     }
178                 }
179                 else
180                 {
181                     if (freeINodeList.IsEmpty())
182                     {
183                         throw SystemError(ERLIMITEXCEEDED"no free inodes in inode cache");
184                     }
185                     INode* inode = freeINodeList.Front();
186                     void* fiberData = OsGetFiberData();
187                     Process* process = cast<Process*>(fiberData);
188                     inode->SetOwner(process);
189                     freeINodeList.RemoveFirst();
190                     inode->SetIterator(freeINodeList.End());
191                     inodeMap.Remove(inode->Key());
192                     inode->SetKey(key);
193                     inodeMap[key] = inode;
194                     inode->SetFlag(INode.Flags.locked);
195                     FileSystem* fileSystem = GetMountTable().GetFileSystem(key.fsNumber);
196                     int inodeBlockNumber = GetINodeBlockNumber(key.inodeNumberfileSystem->GetFirstINodeBlockNumber());
197                     Block* block = null;
198                     if (fileSystem->LastBlockNumber() < inodeBlockNumber)
199                     {
200                         block = fs->GetBlockManager()->GetBlock(BlockKey(inodeBlockNumberkey.fsNumber)null);
201                         block->Clear();
202                     }
203                     else
204                     {
205                         block = fs->GetBlockManager()->ReadBlock(BlockKey(inodeBlockNumberkey.fsNumber)null);
206                     }
207                     BlockPutter putter(block);
208                     INodeBlock* inodeBlock = cast<INodeBlock*>(block);
209                     INode source = inodeBlock->GetINode(GetINodeIndex(key.inodeNumber));
210                     UniquePtr<byte> mem(cast<byte*>(MemAlloc(inodeSize)));
211                     MemoryWriter writer(mem.Get()inodeSize);
212                     source.Write(writer);
213                     MemoryReader reader(mem.Get()inodeSize);
214                     inode->ResetFlags();
215                     inode->Read(reader);
216                     inode->SetFlag(INode.Flags.locked);
217                     inode->SetUseCount(1);
218                     if (inode->GetNumLinks() == 0)
219                     {
220                         inode->SetNumLinks(1);
221                     }
222                     if (Log())
223                     {
224                         LogMessage("fs.root.imgr.getinode.end"inode->ToString());
225                     }
226                     return inode;
227                 }
228             }
229         }
230         public override void PutINode(INode* inode)
231         {
232             if (Log())
233             {
234                 LogMessage("fs.root.imgr.putinode.begin"inode->ToString());
235             }
236             FileSystem* fs = GetMountTable().GetFileSystem(0);
237             inode->SetFlag(INode.Flags.locked);
238             inode->SetUseCount(inode->GetUseCount() - 1);
239             if (inode->GetUseCount() == 0)
240             {
241                 if (Log())
242                 {
243                     LogMessage("fs.root.imgr.putinode.count=0"inode->ToString());
244                 }
245                 if (inode->GetNumLinks() == 0u)
246                 {
247                     if (Log())
248                     {
249                         LogMessage("fs.root.imgr.putinode.nlinks=0"inode->ToString());
250                     }
251                     fs->GetBlockManager()->FreeBlocks(inode);
252                     inode->SetType(FileType.free);
253                     inodeMap.Remove(inode->Key());
254                     FileSystem* fsi = GetMountTable().GetFileSystem(inode->Key().fsNumber);
255                     fsi->SetFreeINodeNumber(inode->Key().inodeNumber);
256                 }
257                 if (inode->GetFlag(INode.Flags.dirty))
258                 {
259                     FileSystem* fileSystem = GetMountTable().GetFileSystem(inode->Key().fsNumber);
260                     int inodeBlockNumber = GetINodeBlockNumber(inode->Key().inodeNumberfileSystem->GetFirstINodeBlockNumber());
261                     Block* block = null;
262                     if (fileSystem->LastBlockNumber() < inodeBlockNumber)
263                     {
264                         block = fileSystem->GetBlockManager()->GetBlock(BlockKey(inodeBlockNumberinode->Key().fsNumber)null);
265                         block->Clear();
266                     }
267                     else
268                     {
269                         block = fileSystem->GetBlockManager()->ReadBlock(BlockKey(inodeBlockNumberinode->Key().fsNumber)null);
270                     }
271                     BlockPutter putter(block);
272                     INodeBlock* inodeBlock = cast<INodeBlock*>(block);
273                     inodeBlock->SetINode(GetINodeIndex(inode->Key().inodeNumber)*inode);
274                     block->SetFlag(Block.Flags.dirty);
275                     fileSystem->GetBlockManager()->WriteBlock(blocknull);
276                     inode->ResetFlag(INode.Flags.dirty);
277                 }
278                 freeINodeList.Add(inode);
279                 inode->SetIterator(LinkedList<INode*>.Iterator(&freeINodeListfreeINodeList.Tail()));
280                 inode->ResetOwner();
281             }
282             inode->ResetFlag(INode.Flags.locked);
283             Kernel& kernel = GetKernel();
284             ProcessTable& processTable = kernel.GetProcessTable();
285             List<Process*> waitingProcesses = inode->GetWaitingProcesses();
286             for (Process* process : waitingProcesses)
287             {
288                 WakeUpProcess(processTableprocess);
289             }
290             if (Log())
291             {
292                 LogMessage("fs.root.imgr.putinode.end"inode->ToString());
293             }
294         }
295         public override INode* PathToINode(Process* processconst string& path)
296         {
297             DirectorySlot freeDirectorySlot;
298             INode* parent = null;
299             string name;
300             return PathToINode(processpathPathToINodeFlags.noneparentfreeDirectorySlotname);
301         }
302         public override INode* PathToINode(Process* processconst string& pathPathToINodeFlags flagsINode*& parentDirectorySlot& freeDirectorySlotstring& name)
303         {
304             if (Log())
305             {
306                 LogMessage("fs.root.imgr.pathtoinode.begin"path);
307             }
308             bool createEntry = (flags & PathToINodeFlags.createEntry) != PathToINodeFlags.none;
309             bool ignoreMountPoint = (flags & PathToINodeFlags.ignoreMountPoint) != PathToINodeFlags.none;
310             FileSystem* fs = GetMountTable().GetFileSystem(0);
311             if (createEntry)
312             {
313                 DirectorySlot slot;
314                 freeDirectorySlot = slot;
315                 name.Clear();
316             }
317             INode* inode = null;
318             if (path.IsEmpty() || path[0] != '/')
319             {
320                 if (process != null)
321                 {
322                     inode = GetINode(process->workingDirINodeKey);
323                 }
324                 else
325                 {
326                     inode = GetINode(fs->GetRootDirINodeKey());
327                 }
328             }
329             else
330             {
331                 if (process != null)
332                 {
333                     inode = GetINode(process->rootDirINodeKey);
334                 }
335                 else
336                 {
337                     inode = GetINode(fs->GetRootDirINodeKey());
338                 }
339             }
340             if (!createEntry && path == "/")
341             {
342                 return inode;
343             }
344             INodePutter inodePutter(inode);
345             List<string> pathComponents = path.Split('/');
346             long pn = pathComponents.Count();
347             if (pn < 2 && createEntry)
348             {
349                 parent = inode;
350                 inodePutter.ResetINode();
351             }
352             string pc;
353             for (long pi = 0; pi < pn; ++pi;)
354             {
355                 const string& pathComponent = pathComponents[pi];
356                 if (pathComponent.IsEmpty())
357                 {
358                     pc = "/";
359                     if (!createEntry)
360                     {
361                         continue;
362                     }
363                 }
364                 else
365                 {
366                     pc = Path.Combine(pcpathComponent);
367                 }
368                 if (Log())
369                 {
370                     LogMessage("fs.root.imgr.pathtoinode.pc"pc);
371                 }
372                 if (createEntry)
373                 {
374                     if (pi == pn - 1)
375                     {
376                         name = pathComponent;
377                     }
378                     else if (pathComponent.IsEmpty())
379                     {
380                         if (pi == pn - 2)
381                         {
382                             parent = inode;
383                             inodePutter.ResetINode();
384                         }
385                         continue;
386                     }
387                 }
388                 if (inode->Type() == FileType.directory)
389                 {
390                     if (process != null)
391                     {
392                         try
393                         {
394                             inode->CheckPermissions(process->uidprocess->gidAccess.execute);
395                         }
396                         catch (const Exception& ex)
397                         {
398                             throw SystemError(EPERM"cannot browse directory '" + pc + "' using uid " + ToString(process->uid) + ": " + ex.Message());
399                         }
400                         if (inode->Key() == process->rootDirINodeKey && pathComponent == "..") continue;
401                         if (pathComponent == ".") continue;
402                     }
403                     else
404                     {
405                         if (inode->Key() == fs->GetRootDirINodeKey() && pathComponent == "..") continue;
406                         if (pathComponent == ".") continue;
407                     }
408                     long offset = 0;
409                     long directorySize = inode->GetFileSize();
410                     bool found = false;
411                     while (offset < directorySize && !found)
412                     {
413                         int blockNumber = 0;
414                         int blockOffset = 0;
415                         fs->GetBlockManager()->GetBlockNumber(inodeoffsetblockNumberblockOffsetfalse);
416                         if (blockNumber == 0)
417                         {
418                             return null;
419                         }
420                         Block* block = fs->GetBlockManager()->ReadBlock(BlockKey(blockNumberinode->Key().fsNumber)null);
421                         BlockPutter blockPutter(block);
422                         DirectoryBlock* directoryBlock = cast<DirectoryBlock*>(block);
423                         for (int i = 0; i < numDirectoryEntriesInBlock; ++i;)
424                         {
425                             DirectoryEntry entry = directoryBlock->GetDirectoryEntry(i);
426                             if (entry.inodeNumber == 0)
427                             {
428                                 if (createEntry && pi == pn - 1 && freeDirectorySlot.offset == -1)
429                                 {
430                                     DirectorySlot slot(blockNumberinode->Key().fsNumberoffset);
431                                     freeDirectorySlot = slot;
432                                 }
433                                 offset = offset + directoryEntrySize;
434                                 continue;
435                             }
436                             if (pathComponent == entry.name)
437                             {
438                                 inode = GetINode(INodeKey(entry.inodeNumberinode->Key().fsNumber));
439                                 if (!ignoreMountPoint && inode->GetFlag(INode.Flags.mountPoint))
440                                 {
441                                     inodePutter.ResetINode(inode);
442                                     FileSystem* mountedFileSystem = GetMountTable().GetMountedFileSystem(pcinode->Key());
443                                     if (createEntry && mountedFileSystem->IsReadOnly())
444                                     {
445                                         throw SystemError(EFAIL"cannot create entry: mounted file system '" + mountedFileSystem->Name() + "' is read-only");
446                                     }
447                                     string subPath;
448                                     if (pi < pn - 1)
449                                     {
450                                         subPath = pathComponents[pi + 1];
451                                         for (long spi = pi + 2; spi < pn; ++spi;)
452                                         {
453                                             subPath = Path.Combine(subPathpathComponents[spi]);
454                                         }
455                                     }
456                                     INodeManager* imgr = mountedFileSystem->GetINodeManager();
457                                     return CallPathToINode(imgrprocesssubPath);
458                                 }
459                                 if (createEntry && pi == pn - 2)
460                                 {
461                                     parent = inode;
462                                 }
463                                 else
464                                 {
465                                     inodePutter.ResetINode(inode);
466                                 }
467                                 found = true;
468                                 break;
469                             }
470                             offset = offset + directoryEntrySize;
471                         }
472                     }
473                     if (!found)
474                     {
475                         if (pi == pn - 1)
476                         {
477                             if (createEntry && freeDirectorySlot.offset == -1)
478                             {
479                                 DirectorySlot slot(invalidBlockNumberinode->Key().fsNumberoffset);
480                                 freeDirectorySlot = slot;
481                             }
482                             return null;
483                         }
484                         else if (pi < pn - 1 && process != null)
485                         {
486                             throw SystemError(ENOENT"directory '" + pc + "' not found");
487                         }
488                     }
489                 }
490                 else
491                 {
492                     if (process != null)
493                     {
494                         throw SystemError(EINVAL"path component '" + pathComponent + "' does not denote a directory");
495                     }
496                 }
497             }
498             inodePutter.ResetINode();
499             if (Log())
500             {
501                 LogMessage("fs.root.imgr.pathtoinode.end"inode->ToString());
502             }
503             return inode;
504         }
505         private void RemoveINodeFromFreeList(INode* inode)
506         {
507             LinkedList<INode*>.Iterator iterator = inode->GetIterator();
508             if (iterator != freeINodeList.End())
509             {
510                 freeINodeList.Remove(iterator);
511                 inode->SetIterator(freeINodeList.End());
512             }
513         }
514         private HashMap<INodeKeyINode*INodeKeyHash> inodeMap;
515         private LinkedList<INode*> freeINodeList;
516         private List<UniquePtr<INode>> inodes;
517     }
518 }