/// <summary> /// Adds inodes for each dir. /// </summary> void addDirInodes() { inodes.Add(root.ino); foreach (var dir in allDirs) { var ino = new PfsDinode32 { Mode = InodeMode.dir | InodeMode.rwx, Number = (uint)inodes.Count, Blocks = 1, Size = 65536 }; dir.ino = ino; dir.Dirents.Add(new PfsDirent { Name = ".", InodeNumber = ino.Number, Type = 4 }); dir.Dirents.Add(new PfsDirent { Name = "..", InodeNumber = dir.Parent.ino.Number, Type = 5 }); dirents.Add(dir.Dirents); var dirent = new PfsDirent { Name = dir.name, InodeNumber = (uint)inodes.Count, Type = 3 }; dir.Parent.Dirents.Add(dirent); dir.Parent.ino.Nlink++; inodes.Add(ino); } }
/// <summary> /// Adds inodes for each dir. /// </summary> void addDirInodes() { inodes.Add(properties.root.ino); foreach (var dir in allDirs.OrderBy(x => x.FullPath())) { var ino = MakeInode( Mode: InodeMode.dir | inode.RXOnly, Number: (uint)inodes.Count, Blocks: 1, Size: 65536, Flags: InodeFlags.@readonly, Nlink: 2 // 1 link each for its own dirent and its . dirent ); dir.ino = ino; dir.Dirents.Add(new PfsDirent { Name = ".", InodeNumber = ino.Number, Type = DirentType.Dot }); dir.Dirents.Add(new PfsDirent { Name = "..", InodeNumber = dir.Parent.ino.Number, Type = DirentType.DotDot }); var dirent = new PfsDirent { Name = dir.name, InodeNumber = (uint)inodes.Count, Type = DirentType.Directory }; dir.Parent.Dirents.Add(dirent); dir.Parent.ino.Nlink++; inodes.Add(ino); } }
private Dir LoadDir(uint dinode, Dir parent, string name) { // 100M blocks is enough for a 6TB file. const int MAX_BLOCKS = 100_000_000; var ret = new Dir() { name = name, parent = parent }; var ino = dinodes[dinode]; var postLoad = new List <Func <Dir> >(); var blocks = (int)ino.Blocks; if (blocks < 1 || ino.StartBlock < 1 || ino.StartBlock > MAX_BLOCKS || blocks > MAX_BLOCKS) { throw new Exception($"inode {dinode} is corrupt. "); } foreach (var x in Enumerable.Range(ino.StartBlock, blocks)) { var position = hdr.BlockSize * x; reader.Read(position, sectorBuf, 0, sectorBuf.Length); sectorStream.Position = 0; while (position < hdr.BlockSize * (x + 1)) { var dirent = PfsDirent.ReadFromStream(sectorStream); if (dirent.EntSize == 0) { break; } switch (dirent.Type) { case DirentType.File: ret.children.Add(LoadFile(dirent.InodeNumber, ret, dirent.Name)); break; case DirentType.Directory: postLoad.Add(() => LoadDir(dirent.InodeNumber, ret, dirent.Name)); break; case DirentType.Dot: break; case DirentType.DotDot: break; default: break; } position += dirent.EntSize; } } foreach (var p in postLoad) { ret.children.Add(p()); } return(ret); }
public static Tuple <FlatPathTable, CollisionResolver> Create(List <FSNode> nodes) { var hashMap = new SortedDictionary <uint, uint>(); var nodeMap = new Dictionary <uint, List <FSNode> >(); bool collision = false; foreach (var n in nodes) { var hash = HashFunction(n.FullPath()); if (hashMap.ContainsKey(hash)) { hashMap[hash] = 0x80000000; nodeMap[hash].Add(n); collision = true; } else { hashMap[hash] = n.ino.Number | (n is FSDir ? 0x20000000u : 0u); nodeMap[hash] = new List <FSNode>(); nodeMap[hash].Add(n); } } if (!collision) { return(Tuple.Create(new FlatPathTable(hashMap), (CollisionResolver)null)); } uint offset = 0; var colEnts = new List <List <PfsDirent> >(); foreach (var kv in hashMap.Where(kv => kv.Value == 0x80000000).ToList()) { hashMap[kv.Key] = 0x80000000 | offset; var entList = new List <PfsDirent>(); colEnts.Add(entList); foreach (var node in nodeMap[kv.Key]) { var d = new PfsDirent() { InodeNumber = node.ino.Number, Type = node is FSDir ? DirentType.Directory : DirentType.File, Name = node.FullPath(), }; entList.Add(d); offset += (uint)d.EntSize; } offset += 0x18; } return(Tuple.Create(new FlatPathTable(hashMap), new CollisionResolver(colEnts))); }
private Dir LoadDir(uint dinode, Node parent, string name) { var ret = new Dir() { name = name, parent = parent }; var ino = dinodes[dinode]; var postLoad = new List <Func <Dir> >(); foreach (var x in Enumerable.Range(ino.StartBlock, (int)ino.Blocks)) { var position = hdr.BlockSize * x; reader.Read(position, sectorBuf, 0, sectorBuf.Length); sectorStream.Position = 0; while (position < hdr.BlockSize * (x + 1)) { var dirent = PfsDirent.ReadFromStream(sectorStream); if (dirent.EntSize == 0) { break; } switch (dirent.Type) { case DirentType.File: ret.children.Add(LoadFile(dirent.InodeNumber, ret, dirent.Name)); break; case DirentType.Directory: postLoad.Add(() => LoadDir(dirent.InodeNumber, ret, dirent.Name)); break; case DirentType.Dot: break; case DirentType.DotDot: break; default: break; } position += dirent.EntSize; } } foreach (var p in postLoad) { ret.children.Add(p()); } return(ret); }
public static PfsDirent ReadFromStream(Stream s) { var pos = s.Position; var d = new PfsDirent { InodeNumber = s.ReadUInt32LE(), Type = (DirentType)s.ReadInt32LE(), NameLength = s.ReadInt32LE(), EntSize = s.ReadInt32LE(), }; d.name = s.ReadASCIINullTerminated(d.NameLength); s.Position = pos + d.EntSize; return(d); }
/// <summary> /// Adds inodes for each file. /// </summary> void addFileInodes() { foreach (var file in allFiles) { var ino = new PfsDinode32 { Mode = InodeMode.file | InodeMode.rwx, Size = file.Size, SizeCompressed = file.Size, Number = (uint)inodes.Count, Blocks = (uint)CeilDiv(file.Size, hdr.BlockSize) }; file.ino = ino; var dirent = new PfsDirent { Name = file.name, Type = 2, InodeNumber = (uint)inodes.Count }; file.Parent.Dirents.Add(dirent); inodes.Add(ino); } }
/// <summary> /// Adds inodes for each file. /// </summary> void addFileInodes() { foreach (var file in allFiles.OrderBy(x => x.FullPath())) { var ino = MakeInode( Mode: InodeMode.file | inode.RXOnly, Size: file.Size, SizeCompressed: file.CompressedSize, Number: (uint)inodes.Count, Blocks: (uint)CeilDiv(file.Size, hdr.BlockSize), Flags: InodeFlags.@readonly | (file.Compress ? InodeFlags.compressed : 0) ); if (properties.Sign) // HACK: Outer PFS images don't use readonly? { ino.Flags &= ~InodeFlags.@readonly; } file.ino = ino; var dirent = new PfsDirent { Name = file.name, Type = DirentType.File, InodeNumber = (uint)inodes.Count }; file.Parent.Dirents.Add(dirent); inodes.Add(ino); } }