Skip to content

Commit d3935c8

Browse files
committed
Ensure unique top-level directories for archives when using 'nomerge'
- Align mount-zip behavior with fuse-archive: archives with identical base names are uniquely renamed (e.g., 'archive', 'archive (1)') rather than merged. - Implement this by creating and attaching a unique Node for the archive directory before scanning its contents. - Correctly increment the root node's link count for each new archive directory. - Verify that mounting two archives with the same base name using the 'nomerge' option results in uniquely named top-level directories (e.g., 'empty' and 'empty (1)'). - Add a complex test case mounting 'hlink-relative.zip' twice with '-o nomerge'. - Verify that both regular files and hard links are correctly resolved within their respective uniquely-named archive directories.
1 parent d21c18c commit d3935c8

3 files changed

Lines changed: 67 additions & 1 deletion

File tree

lib/tree.cc

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,9 +512,19 @@ Tree::Tree(std::span<const std::string> paths, Options opts)
512512
for (const auto& [zip, zip_path] : zips_) {
513513
path = '/';
514514
if (!opts_.merge) {
515-
path += Path(zip_path).Split().second.WithoutExtension();
515+
Node::Ptr archive_node(new Node{
516+
.parent = root_,
517+
.name = std::string(Path(zip_path).Split().second.WithoutExtension()),
518+
.mode = S_IFDIR | 0755,
519+
.nlink = 2});
520+
Node* const node = RenameIfCollision(std::move(archive_node));
521+
root_->AddChild(node);
522+
root_->nlink++;
523+
path += node->name;
516524
}
517525

526+
assert(path.capacity() >= PATH_MAX);
527+
518528
const std::string archive_prefix = path;
519529
size_t const initial_path_length = path.size();
520530

tests/node_test.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222

2323
namespace {
2424

25+
TEST(NodeTest, StaticSize) {
26+
EXPECT_LE(sizeof(Node), 256);
27+
}
28+
2529
TEST(NodeTest, Basic) {
2630
Node root{};
2731
root.name = "/";

tests/test.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,58 @@ def TestMultiple():
15801580
options=['-o', 'nomerge'],
15811581
)
15821582

1583+
want_tree = {
1584+
'.': {'ino': 1, 'mode': 'drwxr-xr-x', 'nlink': 4},
1585+
'empty': {'ino': 2, 'mode': 'drwxr-xr-x', 'nlink': 2},
1586+
'empty (1)': {'ino': 3, 'mode': 'drwxr-xr-x', 'nlink': 2},
1587+
}
1588+
1589+
MountArchiveAndCheckTree(
1590+
['empty.zip', 'empty.zip'],
1591+
want_tree,
1592+
options=['-o', 'nomerge'],
1593+
)
1594+
1595+
want_tree = {
1596+
'.': {'ino': 1, 'mode': 'drwxr-xr-x', 'nlink': 4},
1597+
'hlink-relative': {'ino': 2, 'mode': 'drwxr-xr-x', 'nlink': 2},
1598+
'hlink-relative/0regular': {
1599+
'ino': 3,
1600+
'mode': '-rw-r--r--',
1601+
'nlink': 2,
1602+
'size': 10,
1603+
'md5': 'e09c80c42fda55f9d992e59ca6b3307d',
1604+
},
1605+
'hlink-relative/hlink': {
1606+
'ino': 3,
1607+
'mode': '-rw-r--r--',
1608+
'nlink': 2,
1609+
'size': 10,
1610+
'md5': 'e09c80c42fda55f9d992e59ca6b3307d',
1611+
},
1612+
'hlink-relative (1)': {'ino': 5, 'mode': 'drwxr-xr-x', 'nlink': 2},
1613+
'hlink-relative (1)/0regular': {
1614+
'ino': 6,
1615+
'mode': '-rw-r--r--',
1616+
'nlink': 2,
1617+
'size': 10,
1618+
'md5': 'e09c80c42fda55f9d992e59ca6b3307d',
1619+
},
1620+
'hlink-relative (1)/hlink': {
1621+
'ino': 6,
1622+
'mode': '-rw-r--r--',
1623+
'nlink': 2,
1624+
'size': 10,
1625+
'md5': 'e09c80c42fda55f9d992e59ca6b3307d',
1626+
},
1627+
}
1628+
1629+
MountArchiveAndCheckTree(
1630+
['hlink-relative.zip', 'hlink-relative.zip'],
1631+
want_tree,
1632+
options=['-o', 'nomerge'],
1633+
)
1634+
15831635

15841636
# Tests -o dmask, fmask and default_permissions.
15851637
def TestMasks():

0 commit comments

Comments
 (0)