From 3647c3835805a0a8934696855e7ce1c11af74953 Mon Sep 17 00:00:00 2001 From: Dario Ciccone Date: Thu, 29 Mar 2018 12:25:01 +0200 Subject: [PATCH] Adding symbolic link file type support to ZipFile::Builder::Item to handle symlinks while creating archives in MacOSX/Linux --- modules/juce_core/zip/juce_ZipFile.cpp | 39 +++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/modules/juce_core/zip/juce_ZipFile.cpp b/modules/juce_core/zip/juce_ZipFile.cpp index 933bf4360..92cccc77d 100644 --- a/modules/juce_core/zip/juce_ZipFile.cpp +++ b/modules/juce_core/zip/juce_ZipFile.cpp @@ -451,15 +451,18 @@ Result ZipFile::uncompressEntry (int index, const File& targetDirectory, bool sh struct ZipFile::Builder::Item { Item (const File& f, InputStream* s, int compression, const String& storedPath, Time time) - : file (f), stream (s), storedPathname (storedPath), fileTime (time), compressionLevel (compression) + : file (f), stream (s), storedPathname (storedPath), fileTime (time), compressionLevel (compression), isSymbolicLink(0) { +#if (defined (JUCE_MAC) || defined (JUCE_LINUX) || defined (JUCE_BSD)) + isSymbolicLink = (file.exists() && file.isSymbolicLink()); +#endif } bool writeData (OutputStream& target, const int64 overallStartPosition) { MemoryOutputStream compressedData ((size_t) file.getSize()); - if (compressionLevel > 0) + if (compressionLevel > 0 && !isSymbolicLink) { GZIPCompressorOutputStream compressor (compressedData, compressionLevel, GZIPCompressorOutputStream::windowBitsRaw); @@ -486,12 +489,25 @@ struct ZipFile::Builder::Item bool writeDirectoryEntry (OutputStream& target) { target.writeInt (0x02014b50); - target.writeShort (20); // version written + + //symbolic link should set UNIX made system to handle external attributes field + target.writeShort (isSymbolicLink ? 0x0314 : 0x0014); // version written (lower byte) & file attribute compatibility (higher byte) + writeFlagsAndSizes (target); target.writeShort (0); // comment length target.writeShort (0); // start disk num target.writeShort (0); // internal attributes - target.writeInt (0); // external attributes + + // for symbolic links we use BSD masks for file types + // 0xA1ED translates to 0120755 in base 8, i.e.: + // 12 -> #define S_IFLNK 0120000 /* symbolic link */ + // 0 -> no suid bit + // 7 -> RWX permissions for owner + // 5 -> R_X permissions for group + // 5 -> R_X permissions for other + // ref: https://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute/14727#14727 + target.writeInt (isSymbolicLink ? 0xA1ED0000 : 0); // external attributes + target.writeInt ((int) (uint32) headerStart); target << storedPathname; @@ -506,6 +522,7 @@ private: int64 compressedSize = 0, uncompressedSize = 0, headerStart = 0; int compressionLevel = 0; unsigned long checksum = 0; + bool isSymbolicLink = false; static void writeTimeAndDate (OutputStream& target, Time t) { @@ -517,7 +534,19 @@ private: { if (stream == nullptr) { + if (isSymbolicLink) + { + String linkTarget = file.getLinkedTarget().getRelativePathFrom(file); + size_t bufferSize = linkTarget.toUTF8().sizeInBytes() - 1; + const char* buffer = linkTarget.toRawUTF8(); + ScopedPointer targetPathStringStream (new MemoryInputStream(buffer, bufferSize, true)); + + stream.reset (targetPathStringStream.release()); + } + else + { stream.reset (file.createInputStream()); + } if (stream == nullptr) return false; @@ -548,7 +577,7 @@ private: { target.writeShort (10); // version needed target.writeShort ((short) (1 << 11)); // this flag indicates UTF-8 filename encoding - target.writeShort (compressionLevel > 0 ? (short) 8 : (short) 0); + target.writeShort ((!isSymbolicLink && compressionLevel > 0) ? (short) 8 : (short) 0); //symlink target path is not compressed writeTimeAndDate (target, fileTime); target.writeInt ((int) checksum); target.writeInt ((int) (uint32) compressedSize); -- 2.15.1