简体   繁体   中英

Dealing with unix symlink files on Windows filesystem

I'm currently working on a Java project which should enable the user to export projects bundled with Windows software (.exe) or OS X app (.app) to distribute the data to other workstations. Both the Windows and OS X software are stored as a compressed zip file and uncompressed in case the project is exported. My issue is that unzipping the OS X app on Windows breaks the symbolic links inside bundled frameworks. This, in turn, breaks the app's signature and causes issues when the app is started on OS X.

I'm using Apache Commons compress libraries to uncompress the packages, which enables me to detect symbolic links and their target. With OS X, I'm able to recreate the symbolic link with methods from java.nio.file.Files, but with Windows this would require administrator privileges, which I'm a bit hesitant to add as a prerequisite to use the software (even if enabled I'm not confident this would work - haven't tried).

I have a little understanding of the reason why the links are broken, but if I understood correctly the Windows file system does not include support for the file type of Unix symbolic link, and hence the link is unzipped as a normal file and will no longer be recognized as a symlink when opened on OS X.

So, my question is that can I somehow just bitwise copy the symbolic link file to Windows file system preserving the Unix specific bits or is preserving this information downright impossible? Or should I just change the export method to add the project files to existing zip file, in which case symlink information would probably be preserved until the zip is extracted on the target machine?

The current code looping over each ZipArchiveEntry of the ZipFile is as below:

byte data[] = new byte[BUFFER];

Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();

while (entries.hasMoreElements()) {
    ZipArchiveEntry zipEntry = entries.nextElement();
    String destFilename = copyFolder + zipEntry.getName();
    File destFile = new File(destFilename);

    if (zipEntry.isUnixSymlink()) {             
        File target = new File(zipFile.getUnixSymlink(zipEntry));              
        try {   
            // Try to create symbolic link - currently only works with OS X
            Files.createSymbolicLink(destFile.toPath(), target.toPath());
            continue;
        } catch (Exception e) {
            System.out.println("Failed to create symbolic link: " + 
                destFile.getAbsolutePath() + " -> " + 
                target.getAbsolutePath());
        }
    }

    // If file
    int count;
    FileOutputStream fos = new FileOutputStream(destFile);

    try (BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER)) {
        InputStream is = zipFile.getInputStream(zipEntry);
        while ( (count = is.read(data, 0, BUFFER)) != -1) {
            dest.write(data, 0, count);
        }
    }
}

Windows file system uses similar approach as UNIX to define what symlink is (like hard- or soft- links), but they are not 100% compatible. You can read more about that here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365680(v=vs.85).aspx The simple answer to you question - you can't just bitwise copy links to have the same Unix specific bits, because Windows NTFS just don't have them. JAVA is also designed to work in a sandbox, so you don't have access to system low-level API in order to make "whatever you want". I wouldn't go for such system-specific task with JAVA. Probably you will not have to.

Depends on your role at this project you can re-define what bundle should contain. Do you really need symlinks inside? May be it is more universal to have some kind of "property" file that maps different parts together? Or distribute it as database? Try not to depend from system specific realization.

You will need a Windows specific and "non-standard" (for Java at least) approach to solve this problem, since there is not a standard cross-platform Java way to solve it. For instance, you could attempt to use Runtime.exec alongside a call to the "mklink" utility . The "mklink" command allows the creation of hard and soft(symbolic) links and also the creation of junctions- basically it creates the various types of re-parse points available to a Windows filesystem. If you are willing to access native code then you also may be able to use the pre-made JNA mapping to Kernel32.dll or write a custom mapping to Kernel32.dll and call the WinBase.h provided method CreateSymbolicLink(LPTSTR,LPTSTR,DWORD) .

In general, I'd advise you to avoid symlinks and hardlinks on Windows at all, if possible.

Symlinks and Hardlinks have been introduced into Windows quite late, and support for it is rather poor:

  • Most Windows users don't expect symlinks in their filesystem
  • Symlinks are only supported locally on the NTFS file system, and not on other filesystems (FAT, exFAT, UDF) or via network shares
  • Third-party tools (Zipper, backup tools, cloud sync software) and also some Microsoft software (eg File Version History, ie Windows' "Time Machine"; or the Windows explorer when copying/moving a folder) cannot cope with symlinks or hardlinks, either resolving them or crashing/showing an error message).
  • Permissions required to create them vary by Windows version (on Windows 7, a regular user can create a symlink (junction) to a directory he can access, but on Windows XP you need Admin privileges in any case)

Therefore, as you need the symlinks only temporarily (as you wrote in the comments) and later zip up the files again, I'd suggest that when unzipping you create your own marker files to denote symlinks, and later when zipping you convert them back to proper UNIX symlinks in the ZIP files.

It has been 6 years, if you compress the macOS app bundle on Windows, and then decompress the same ZIP later on Windows, it will reserve the alias files in macOS bundle (mostly inside the Frameworks folder).

As you said, you can also keep the macOS app as a ZIP package, and have users to decompress it when needed (most likely on macOS), then it will also work.

Compressing a macOS app bundle on Linux and decompress on macOS also works, but won't work on Windows.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM