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 are placed in the wrong locations #524

Open
wkgcass opened this issue Nov 15, 2023 · 0 comments
Open

Symlinks to directories are placed in the wrong locations #524

wkgcass opened this issue Nov 15, 2023 · 0 comments

Comments

@wkgcass
Copy link

wkgcass commented Nov 15, 2023

Abstract

Symlinks to directories are placed in the wrong locations.

For example, I have a directory named a, and a symlink pointing to it named b (b -> a), and they are put in the same root directory.

When I use zip4j to compress the root directory by calling params.setSymbolicLinkAction(INCLUDE_LINK_ONLY) and zip.addFolder(dirFile, params), the symlink b is placed at a/b.

I discovered this problem when I was trying to pack a symlink file node_modules/log-facade -> ../app/log, the unzip result is node_modules/log/log-facade -> ../app/log, where log-facade is replaced with the pointing directory's name log and created as a directory, and log-facade symlink is placed inside the log/ directory.

Details

click to reveal

Construct a directory structure:

mkdir test-zip
cd test-zip

mkdir a
echo "xx" > a/x
ln -s a b
mkdir c
echo "dd" > c/d
mkdir e
ln -s '../c/d' e/f

cd ../

The tree result would be (please ignore the testing .java,.jar,.class files):

.
├── Main.class
├── Main.java
├── test-zip
│   ├── a
│   │   └── x
│   ├── b -> a
│   ├── c
│   │   └── d
│   └── e
│       └── f -> ../c/d
└── zip4j-2.11.5.jar

5 directories, 6 files

You can test their validity by cat test-zip/b/x and cat test-zip/e/f

results of zip command

Run: zip --symlinks -r test-zip.zip ./test-zip

Move the test-zip.zip somewhere else and run unzip test-zip.zip, I can get the output:

Archive:  test-zip.zip
   creating: test-zip/
   creating: test-zip/a/
 extracting: test-zip/a/x
   creating: test-zip/c/
 extracting: test-zip/c/d
   creating: test-zip/e/
    linking: test-zip/e/f            -> ../c/d
    linking: test-zip/b              -> a
finishing deferred symbolic links:
  test-zip/e/f           -> ../c/d
  test-zip/b             -> a

and tree output:

.
├── test-zip
│   ├── a
│   │   └── x
│   ├── b -> a
│   ├── c
│   │   └── d
│   └── e
│       └── f -> ../c/d
└── test-zip.zip

5 directories, 4 files

results of zip4j

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

import java.io.File;

public class Main {
    public static void main(String[] args) throws Exception {
        ZipFile f = new ZipFile("test-zip.zip");
        ZipParameters params = new ZipParameters();
        params.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
        f.addFolder(new File("test-zip"), params);
    }
}

Run:

javac -cp ./zip4j-2.11.5.jar Main.java
java -cp ./zip4j-2.11.5.jar:. Main

unzip result:

Archive:  test-zip.zip
   creating: test-zip/a/
  inflating: test-zip/a/x
   creating: test-zip/c/
  inflating: test-zip/c/d
   creating: test-zip/e/
    linking: test-zip/e/f            -> ../c/d
    linking: test-zip/a/b            -> a
finishing deferred symbolic links:
  test-zip/e/f           -> ../c/d
  test-zip/a/b           -> a

tree output:

.
├── test-zip
│   ├── a
│   │   ├── b -> a
│   │   └── x
│   ├── c
│   │   └── d
│   └── e
│       └── f -> ../c/d
└── test-zip.zip

4 directories, 5 files

Some debug into the code

In FileUtils.java#L221, it says:

        if (isSymbolicLink(fileToAdd)) {
          String rootPath = new File(fileToAdd.getParentFile().getCanonicalFile().getPath() + File.separator + fileToAdd.getCanonicalFile().getName()).getPath();
          tmpFileName = rootPath.substring(rootFolderFileRef.length());
        } else {

If the file is a symlink, then the getCanonicalFile() will return the pointing directory/file's File instead of the symbolic file's own File, so the getCanonicalFile().getName() returns the pointing directory/file's name.

So, for symlinks pointing to directories, the code will silently put them to the wrong location.

As for symlinks to files, the rootPath will also be incorrect, but in the code addSymlinkToZip it calls replaceFileNameInZip, which trims the filename, and appends the symlink's file name, which eventually will be correct.

This doesn't fix the wrong location of directories' symlinks because they have a trailing /.
Also, there will always be an additional directory for symlinks to directories, because the code shows that the symlink's name will always be appended.


I hope this could be fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant