Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ let package = Package(
name: "ContainerizationEXT4",
dependencies: [
"ContainerizationArchive",
.product(name: "OrderedCollections", package: "swift-collections"),
.product(name: "SystemPackage", package: "swift-system"),
"ContainerizationOS",
],
Expand Down
34 changes: 20 additions & 14 deletions Sources/ContainerizationEXT4/EXT4+FileTree.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@
//===----------------------------------------------------------------------===//

import Foundation
import OrderedCollections
import SystemPackage

extension EXT4 {
class FileTree {
class FileTreeNode {
let inode: InodeNumber
let name: String
var children: [Ptr<FileTreeNode>] = []
// Children keyed by name for O(1) lookup, preserving insertion order.
private(set) var childrenByName: OrderedDictionary<String, Ptr<FileTreeNode>> = [:]
var children: OrderedDictionary<String, Ptr<FileTreeNode>>.Values {
childrenByName.values
}
var blocks: (start: UInt32, end: UInt32)?
var additionalBlocks: [(start: UInt32, end: UInt32)]?
var link: InodeNumber?
Expand All @@ -39,16 +44,17 @@ extension EXT4 {
) {
self.inode = inode
self.name = name
self.children = children
self.blocks = blocks
self.additionalBlocks = additionalBlocks
self.link = link
self.parent = parent
for child in children {
self.addChild(child)
}
}

deinit {
self.children.removeAll()
self.children = []
self.childrenByName.removeAll()
self.blocks = nil
self.additionalBlocks = nil
self.link = nil
Expand All @@ -64,6 +70,14 @@ extension EXT4 {
let path = components.reversed().joined(separator: "/")
return FilePath(path).lexicallyNormalized()
}

func addChild(_ child: Ptr<FileTreeNode>) {
childrenByName[child.pointee.name] = child
}

func removeChild(named name: String) {
childrenByName.removeValue(forKey: name)
}
}

var root: Ptr<FileTreeNode>
Expand All @@ -82,18 +96,10 @@ extension EXT4 {
return node
}
for component in components {
var found = false
for childPtr in node.pointee.children {
let child = childPtr.pointee
if child.name == component {
node = childPtr
found = true
break
}
}
guard found else {
guard let childPtr = node.pointee.childrenByName[component] else {
return nil
}
node = childPtr
}
return node
}
Expand Down
8 changes: 3 additions & 5 deletions Sources/ContainerizationEXT4/EXT4+Formatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ extension EXT4 {
blocks: nil,
link: targetNode.inode
))
parentTreeNode.children.append(linkTreeNodePtr)
parentTreeNode.addChild(linkTreeNodePtr)
parentTreeNodePtr.pointee = parentTreeNode
}

Expand Down Expand Up @@ -254,9 +254,7 @@ extension EXT4 {
}
}
parentInodePtr.pointee = parentInode
parentNode.children.removeAll { childPtr in
childPtr.pointee.name == pathComponent
}
parentNode.removeChild(named: pathComponent)
parentNodePtr.pointee = parentNode

if let hardlink = pathNode.link {
Expand Down Expand Up @@ -412,7 +410,7 @@ extension EXT4 {
children: [],
blocks: (startBlock, endBlock)
))
parentTreeNode.children.append(childTreeNodePtr)
parentTreeNode.addChild(childTreeNodePtr)
parentTreeNodePtr.pointee = parentTreeNode
}
childInode.mode = mode
Expand Down
2 changes: 1 addition & 1 deletion Sources/ContainerizationEXT4/EXT4+Reader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ extension EXT4 {
itemTreeNode.blocks = blocks.first
}
let itemTreeNodePtr = Ptr(itemTreeNode)
root.children.append(itemTreeNodePtr)
root.addChild(itemTreeNodePtr)
itemPtr.pointee = root
let itemInode = try self.getInode(number: itemInodeNum)
if itemInode.mode.isDir() {
Expand Down
2 changes: 1 addition & 1 deletion Sources/ContainerizationEXT4/EXT4Reader+Export.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ extension EXT4.EXT4Reader {
format: .paxRestricted, filter: .none, options: [Options.xattrformat(.schily)])
let writer = try ArchiveWriter(configuration: config)
try writer.open(file: archive.url)
var items = self.tree.root.pointee.children
var items = Array(self.tree.root.pointee.children)
let hardlinkedInodes = Set(self.hardlinks.values)
var hardlinkTargets: [EXT4.InodeNumber: FilePath] = [:]

Expand Down
10 changes: 5 additions & 5 deletions Tests/ContainerizationEXT4Tests/TestEXT4Reader+IO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -617,10 +617,10 @@ struct EXT4PathIOTests {
let tree = EXT4.FileTree(EXT4.RootInode, "/")

let dirPtr = EXT4.Ptr(EXT4.FileTree.FileTreeNode(inode: 3, name: "dir", parent: tree.root))
tree.root.pointee.children.append(dirPtr)
tree.root.pointee.addChild(dirPtr)

let filePtr = EXT4.Ptr(EXT4.FileTree.FileTreeNode(inode: 4, name: "file", parent: dirPtr))
dirPtr.pointee.children.append(filePtr)
dirPtr.pointee.addChild(filePtr)

#expect(dirPtr.pointee.path == FilePath("/dir"))
#expect(filePtr.pointee.path == FilePath("/dir/file"))
Expand All @@ -631,10 +631,10 @@ struct EXT4PathIOTests {
let tree = EXT4.FileTree(EXT4.RootInode, ".")

let dirPtr = EXT4.Ptr(EXT4.FileTree.FileTreeNode(inode: 3, name: "dir", parent: tree.root))
tree.root.pointee.children.append(dirPtr)
tree.root.pointee.addChild(dirPtr)

let filePtr = EXT4.Ptr(EXT4.FileTree.FileTreeNode(inode: 4, name: "file", parent: dirPtr))
dirPtr.pointee.children.append(filePtr)
dirPtr.pointee.addChild(filePtr)

#expect(dirPtr.pointee.path == FilePath("dir"))
#expect(filePtr.pointee.path == FilePath("dir/file"))
Expand All @@ -645,7 +645,7 @@ struct EXT4PathIOTests {
let tree = EXT4.FileTree(EXT4.RootInode, "dir")

let filePtr = EXT4.Ptr(EXT4.FileTree.FileTreeNode(inode: 3, name: "file", parent: tree.root))
tree.root.pointee.children.append(filePtr)
tree.root.pointee.addChild(filePtr)

#expect(filePtr.pointee.path == FilePath("dir/file"))
}
Expand Down
Loading