Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Symlinks to directories fail to zip properly #486

Closed
ajpfahnl opened this issue Jan 12, 2023 · 3 comments
Closed

Symlinks to directories fail to zip properly #486

ajpfahnl opened this issue Jan 12, 2023 · 3 comments
Assignees
Labels
bug Something isn't working resolved

Comments

@ajpfahnl
Copy link

Toy example:

I created one directory with a symlink to it and a regular file with a symlink to it like so:

$ mkdir tmp
$ cd tmp
$ mkdir a; ln -s a b; touch c; ln -s c d
$ cd ..
$ tree tmp
tmp
├── a
├── b -> a
├── c
└── d -> c

Ideally what would happen is the following:

$ zip -yr tmp.zip tmp
$ unzip tmp.zip -d newtmp
Archive:  tmp.zip
   creating: newtmp/tmp/
   creating: newtmp/tmp/a/
 extracting: newtmp/tmp/c            
    linking: newtmp/tmp/d            -> c 
    linking: newtmp/tmp/b            -> a 
finishing deferred symbolic links:
  newtmp/tmp/d           -> c
  newtmp/tmp/b           -> a
$ tree newtmp 
newtmp
└── tmp
    ├── a
    ├── b -> a
    ├── c
    └── d -> c

I then attempted to use Zip4j to zip these files.

First attempt is a naive approach. Just setSymbolicLinkAction to INCLUDE_LINK_ONLY:

import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class ZipTest {
    public static void main(String[] args) throws IOException {
        try (ZipFile zipFile = new ZipFile("test.zip");
             Stream<Path> paths = Files.walk(Paths.get("tmp"))) {
            paths.forEach(path -> {
                ZipParameters zp = new ZipParameters();
                if ((!Files.isSymbolicLink(path)) && Files.isDirectory(path)) {
                    zp.setFileNameInZip(path + "/");
                } else {
                    zp.setFileNameInZip(path.toString());
                }
                zp.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
                try {
                    zipFile.addFile(path.toFile(), zp);
                } catch (ZipException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }
}

Let's see what it contains:

$ unzip test.zip -d test && tree test
Archive:  test.zip
   creating: test/tmp/
   creating: test/tmp/a/
 extracting: test/tmp/c              
    linking: test/tmp/d              -> c 
 extracting: test/tmp/b              
finishing deferred symbolic links:
  test/tmp/d             -> c
test
└── tmp
    ├── a
    ├── b
    ├── c
    └── d -> c

2 directories, 3 files

That didn't work. The symlink b to directory a, did not stay a symlink.

Then I tried only setting INCLUDE_LINK_ONLY for paths tested to be symlinks, and manually set CompressionLevel.NO_COMPRESSION and CompressionMethod.STORE.

import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.CompressionLevel;
import net.lingala.zip4j.model.enums.CompressionMethod;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class ZipTest {
    public static void main(String[] args) throws IOException {
        try (ZipFile zipFile = new ZipFile("test.zip");
             Stream<Path> paths = Files.walk(Paths.get("tmp"))) {
            paths.forEach(path -> {
                ZipParameters zp = new ZipParameters();
                if ((!Files.isSymbolicLink(path)) && Files.isDirectory(path)) {
                    zp.setFileNameInZip(path + "/");
                } else {
                    zp.setFileNameInZip(path.toString());
                }
                if (Files.isSymbolicLink(path)) {
                    zp.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
                    zp.setCompressionLevel(CompressionLevel.NO_COMPRESSION);
                    zp.setCompressionMethod(CompressionMethod.STORE);
                }
                try {
                    zipFile.addFile(path.toFile(), zp);
                } catch (ZipException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }
}

Unzipping output:

$ unzip test.zip -d test   
Archive:  test.zip
   creating: test/tmp/
   creating: test/tmp/a/
 extracting: test/tmp/c              
    linking: test/tmp/d              -> c 
 extracting: test/tmp/b              
finishing deferred symbolic links:
  test/tmp/d             -> c

It still won't link b to a!

@srikanth-lingala
Copy link
Owner

Thanks for the detailed analysis of the issue. It always helps to have a detailed description and a code sample to reproduce the issue. I am looking into this issue.

@srikanth-lingala
Copy link
Owner

Fixed in v2.11.4 released today

@ajpfahnl
Copy link
Author

Thank you for working on this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working resolved
Projects
None yet
Development

No branches or pull requests

2 participants