google / fuse-archive

FUSE file system for archives and compressed files (ZIP, RAR, 7Z, ISO, TGZ, XZ...)
Apache License 2.0
166 stars 17 forks source link

Hard links not mounted #18

Closed mattmart3 closed 1 month ago

mattmart3 commented 1 year ago

Hard links produce an error and are not mounted. The issue is likely related to how libarchive handles hard links.

How to reproduce:

  1. Creating a tar.gz archive with two hard linked files
    
    $ echo "testing fs-archive with hard links" > file1

$ ln file1 file2

$ stat file1 file2 File: file1 Size: 35 Blocks: 8 IO Block: 4096 regular file Device: 254,0 Inode: 794969 Links: 2 Access: (0644/-rw-r--r--) Uid: ( 1000/ eugene) Gid: ( 1000/ eugene) Access: 2023-07-31 16:12:00.330384852 +0200 Modify: 2023-07-31 16:12:00.330384852 +0200 Change: 2023-07-31 16:12:07.123700568 +0200 Birth: 2023-07-31 16:12:00.330384852 +0200 File: file2 Size: 35 Blocks: 8 IO Block: 4096 regular file Device: 254,0 Inode: 794969 Links: 2 Access: (0644/-rw-r--r--) Uid: ( 1000/ eugene) Gid: ( 1000/ eugene) Access: 2023-07-31 16:12:00.330384852 +0200 Modify: 2023-07-31 16:12:00.330384852 +0200 Change: 2023-07-31 16:12:07.123700568 +0200 Birth: 2023-07-31 16:12:00.330384852 +0200

$ tar cvaf test_fuse_archive_hard_links.tar.gz file1 file2 file1 file2


2. Mounting with latest fuse-archive fails:

$ git clone https://github.com/google/fuse-archive.git -b v0.1.14 $ cd fuse-archive $ make all $ ./out/fuse-archive ~/test_fuse_archive_hard_links.tar.gz /mnt/tmp fuse-archive: irregular non-link file in /home/eugene/test_fuse_archive_hard_links.tar.gz: /file2 $ ls /mnt/tmp file1


3. Re-extracting the tar.gz works properly and hard links are preserved:

$ mkdir ~/out && tar xvaf ~/test_fuse_archive_hard_links.tar.gz -C ~/out $ stat ~/out/file1 ~/out/file2 File: /home/eugene/out/file1 Size: 35 Blocks: 8 IO Block: 4096 regular file Device: 254,0 Inode: 15874535 Links: 2 Access: (0644/-rw-r--r--) Uid: ( 1000/ eugene) Gid: ( 1000/ eugene) Access: 2023-07-31 16:49:52.049826264 +0200 Modify: 2023-07-31 16:12:00.000000000 +0200 Change: 2023-07-31 16:49:52.049826264 +0200 Birth: 2023-07-31 16:49:52.049826264 +0200 File: /home/eugene/out/file2 Size: 35 Blocks: 8 IO Block: 4096 regular file Device: 254,0 Inode: 15874535 Links: 2 Access: (0644/-rw-r--r--) Uid: ( 1000/ eugene) Gid: ( 1000/ eugene) Access: 2023-07-31 16:49:52.049826264 +0200 Modify: 2023-07-31 16:12:00.000000000 +0200 Change: 2023-07-31 16:49:52.049826264 +0200 Birth: 2023-07-31 16:49:52.049826264 +0200


4. By debugging further, it is clear that the `"regular"` bit flag is not set for the second file.
```patch
diff --git a/src/main.cc b/src/main.cc
index 6afb15f..6c77912 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -1130,6 +1130,8 @@ insert_leaf(struct archive* a,

   std::string symlink;
   mode_t mode = archive_entry_mode(e);
+  mode_t filetype = archive_entry_filetype(e);
+  syslog(LOG_INFO, "AE_IFREG: 0x%04x, file: %s, mode 0x%04x, filetype: 0x%04x\n", AE_IFREG, redact(pathname.c_str()), mode, filetype);
   if (S_ISLNK(mode)) {
     const char* s = archive_entry_symlink_utf8(e);
     if (!s) {
./out/fuse-archive ~/test_fuse_archive_hard_links.tar.gz /mnt/tmp                                                                                                                                          130
fuse-archive: AE_IFREG: 0x8000, file: /file1, mode 0x81a4, filetype: 0x8000
fuse-archive: AE_IFREG: 0x8000, file: /file2, mode 0x01a4, filetype: 0x0000
fuse-archive: irregular non-link file in /home/eugene/test_fuse_archive_hard_links.tar.gz: /file2

A possible solution has already been submitted in PR #11.

fdegros commented 1 year ago

Thanks Matteo for your detailed bug report.

I confirm that hard links are not properly handled by fuse-archive.

The proposed pull request #11 does not solve the issue, at least not just by itself. I tried it. When I apply it, I get two files, but the second one is empty:

$ ls -lh mnt
total 0
-r--r--r-- 1 fdegros primarygroup 35 Aug  4 10:33 file1
-r--r--r-- 1 fdegros primarygroup  0 Aug  4 10:33 file2

In order to fully handle hard links, fuse-archive would require further modifications.