google / archive-patcher Goto Github PK
View Code? Open in Web Editor NEWAutomatically exported from code.google.com/p/archive-patcher
License: Apache License 2.0
Automatically exported from code.google.com/p/archive-patcher
License: Apache License 2.0
it can not work well
I am usinng archive-patcher on Android. I am getting below exception while generating patch, please help me.
2020-07-24 16:19:56.145 920-920/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.apkpatcher, PID: 920
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.apkpatcher/com.example.apkpatcher.MainActivity}:java.lang.NullPointerException: Inflater has been closed
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3623)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3775)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2261)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:8107)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
Caused by: java.lang.NullPointerException: Inflater has been closed
at java.util.zip.Inflater.ensureOpen(Inflater.java:416)
at java.util.zip.Inflater.reset(Inflater.java:370)
at com.google.archivepatcher.generator.DefaultDeflateCompressionDiviner.divineDeflateParameters(DefaultDeflateCompressionDiviner.java:173)
at com.google.archivepatcher.generator.DefaultDeflateCompressionDiviner.divineDeflateParameters(DefaultDeflateCompressionDiviner.java:114)
at com.google.archivepatcher.generator.PreDiffExecutor.generatePreDiffPlan(PreDiffExecutor.java:216)
at com.google.archivepatcher.generator.PreDiffExecutor.prepareForDiffing(PreDiffExecutor.java:157)
at com.google.archivepatcher.generator.FileByFileV1DeltaGenerator.generateDelta(FileByFileV1DeltaGenerator.java:81)
at com.example.apkpatcher.DeltaCounter.generatePatch(DeltaCounter.java:97)
at com.example.apkpatcher.MainActivity.onCreate(MainActivity.java:37)
at android.app.Activity.performCreate(Activity.java:7957)
at android.app.Activity.performCreate(Activity.java:7946)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1307)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3598)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3775)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2261)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:8107)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
2020-07-24 16:21:01.356 1578-1578/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.apkpatcher, PID: 1578
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.apkpatcher/com.example.apkpatcher.MainActivity}: java.lang.NullPointerException: Inflater has been closed
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3623)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3775)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2261)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:8107)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
Caused by: java.lang.NullPointerException: Inflater has been closed
at java.util.zip.Inflater.ensureOpen(Inflater.java:416)
at java.util.zip.Inflater.reset(Inflater.java:370)
at com.google.archivepatcher.generator.DefaultDeflateCompressionDiviner.divineDeflateParameters(DefaultDeflateCompressionDiviner.java:173)
at com.google.archivepatcher.generator.DefaultDeflateCompressionDiviner.divineDeflateParameters(DefaultDeflateCompressionDiviner.java:114)
at com.google.archivepatcher.generator.PreDiffExecutor.generatePreDiffPlan(PreDiffExecutor.java:216)
at com.google.archivepatcher.generator.PreDiffExecutor.prepareForDiffing(PreDiffExecutor.java:157)
at com.google.archivepatcher.generator.FileByFileV1DeltaGenerator.generateDelta(FileByFileV1DeltaGenerator.java:81)
at com.example.apkpatcher.DeltaCounter.generatePatch(DeltaCounter.java:97)
I am using this lib to generate patch from an apk
file. My environment is docker in MacOS. My previous versions of apk file works very fine, but this version does not work :(
I would appreciate it if any suggestions could be given. Now I cannot deploy new versions of my app!
STDOUT: Exception in thread "main" java.util.zip.ZipException: EOCD record not found in last 32k of archive, giving up
STDOUT: at com.google.archivepatcher.generator.MinimalZipArchive.listEntriesInternal(MinimalZipArchive.java:72)
STDOUT: at com.google.archivepatcher.generator.MinimalZipArchive.listEntries(MinimalZipArchive.java:56)
STDOUT: at com.google.archivepatcher.generator.PreDiffExecutor.generatePreDiffPlan(PreDiffExecutor.java:210)
STDOUT: at com.google.archivepatcher.generator.PreDiffExecutor.prepareForDiffing(PreDiffExecutor.java:157)
STDOUT: at com.google.archivepatcher.generator.FileByFileV1DeltaGenerator.generateDelta(FileByFileV1DeltaGenerator.java:81)
STDOUT: at PatchGenerator.main(PatchGenerator.java:36)
Would it be possible to get some more information/instructions on how to properly compile the native generator?
Hi I try to use the applier on an Android device. However, for about 15MB old apk and 2MB patch file, it takes ~8s to complete. It is normal? (Seems to be very slow...) Thanks!
It seems that share
module depends on sharetest
as well as sharetest
depends on share
.
Even if you supply MmapByteSource's to FileByFileDeltaGenerator, it seems to replace them with RandomAccessFileByteSource's.
The current RandomAccessFileByteSource's implementation seems to suffer extremely hard from seeks, an extremely common operation.
Simply swapping ByteSource.fromFile to always return a MmapByteSource greatly improves performance.
When I try the generate a Patch with the Generating a Patch sample code,
The app crash with the the following exception:
FATAL EXCEPTION: main Process: com.rotem.deltaupdatepoc2, PID: 6614 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.rotem.deltaupdatepoc2/com.rotem.deltaupdatepoc2.MainActivity}: java.lang.IllegalStateException: attempt to use Deflater after calling end at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) at android.app.ActivityThread.-wrap11(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: java.lang.IllegalStateException: attempt to use Deflater after calling end at java.util.zip.Deflater.checkOpen(Deflater.java:476) at java.util.zip.Deflater.reset(Deflater.java:355) at com.google.archivepatcher.generator.DefaultDeflateCompressionDiviner.divineDeflateParameters(DefaultDeflateCompressionDiviner.java:183) at com.google.archivepatcher.generator.DefaultDeflateCompressionDiviner.divineDeflateParameters(DefaultDeflateCompressionDiviner.java:104) at com.google.archivepatcher.generator.PreDiffExecutor.generatePreDiffPlan(PreDiffExecutor.java:216) at com.google.archivepatcher.generator.PreDiffExecutor.prepareForDiffing(PreDiffExecutor.java:157) at com.google.archivepatcher.generator.FileByFileV1DeltaGenerator.generateDelta(FileByFileV1DeltaGenerator.java:81) at com.rotem.deltaupdatepoc2.SamplePatchGenerator.generatePatch(SamplePatchGenerator.java:39) at com.rotem.deltaupdatepoc2.MainActivity.cheackForPermissions(MainActivity.java:48) at com.rotem.deltaupdatepoc2.MainActivity.onCreate(MainActivity.java:20) at android.app.Activity.performCreate(Activity.java:6237) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) at android.app.ActivityThread.-wrap11(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Can anyone help please?
The patch applier is close()ing the stream that is passed in because it traps the PartiallyDeflatingOutputStream in a finally block and close()'s there for safety. This should be a flush(), not a close(), as we don't own the output stream that is being used and other operations may need to be performed prior to close().
Don't close() the stream!
Thanks for archive-patcher. It solved my problem on Android. Now , I want to use archive-patcher on iOS, I want to know whether there is a brother project that could support me.
this is the stacktrack.
java.lang.IllegalStateException: setLevel cannot be called after setInput
at java.util.zip.Deflater.setLevel(Deflater.java:428)
at com.google.archivepatcher.generator.DefaultDeflateCompressionDiviner.divineDeflateParameters(DefaultDeflateCompressionDiviner.java:172)
at com.google.archivepatcher.generator.DefaultDeflateCompressionDiviner.divineDeflateParameters(DefaultDeflateCompressionDiviner.java:114)
at com.google.archivepatcher.generator.PreDiffExecutor.generatePreDiffPlan(PreDiffExecutor.java:216)
at com.google.archivepatcher.generator.PreDiffExecutor.prepareForDiffing(PreDiffExecutor.java:157)
at com.google.archivepatcher.generator.FileByFileV1DeltaGenerator.generateDelta(FileByFileV1DeltaGenerator.java:81)
at com.xingbianli.app.MainActivity$1$1.run(MainActivity.java:51)
at java.lang.Thread.run(Thread.java:818)
this is my code.
findViewById(R.id.diff).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
if (!new DefaultDeflateCompatibilityWindow().isCompatible()) {
System.err.println("zlib not compatible on this system");
System.exit(-1);
}
File oldFile = new File(old); // must be a zip archive
File newFile = new File(newversion); // must be a zip archive
Deflater compressor = new Deflater(9, true); // to compress the patch
try {
FileOutputStream patchOut = new FileOutputStream(pat);
DeflaterOutputStream compressedPatchOut =
new DeflaterOutputStream(patchOut, compressor, 32768);
new FileByFileV1DeltaGenerator().generateDelta(oldFile, newFile, compressedPatchOut);
compressedPatchOut.finish();
compressedPatchOut.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
compressor.end();
}
}
}).start();
}
});
Android12上 生成的新文件不是apk格式,解压后少了很多东西
The new DefaultDeflateCompatibilityWindow().isCompatible()
test fails on many Linux distros currently, including: Debian 10, 11, Fedora 32, and Arch, however passes on at least Ubuntu 18.0.4 and 20.04. Tested on OpenJDK 11. This is due to a change in zlib:
commit 43bfaba3d718a27c1b137b1d1aa90d9427ab4a4f
Author: Mark Adler <[email protected]>
Date: Sun Aug 2 00:02:07 2015 -0700
Align deflateParams() and its documentation in zlib.h.
This updates the documentation to reflect the behavior of
deflateParams() when it is not able to compress all of the input
data provided so far due to insufficient output space. It also
assures that data provided is compressed before the parameter
changes, even if at the beginning of the stream.
deflate.c | 3 +--
zlib.h | 38 ++++++++++++++++++++++++++------------
2 files changed, 27 insertions(+), 14 deletions(-)
which is present in zlib v1.2.9, v1.2.10, and v1.2.11.
The original behavior was restored upstream in the develop
branch in
commit f9694097dd69354b03cb8af959094c7f260db0a1
Author: Mark Adler <[email protected]>
Date: Mon Jan 16 09:49:35 2017 -0800
Permit a deflateParams() parameter change as soon as possible.
This commit allows a parameter change even if the input data has
not all been compressed and copied to the application output
buffer, so long as all of the input data has been compressed to
the internal pending output buffer. This also allows an immediate
deflateParams change so long as there have been no deflate calls
since initialization or reset.
which is unreleased - however Ubuntu is manually patching zlib with it in at least 18.04 and 20.04 - which is why those work.
We have additionally discovered disabling caching on the deflate compressor in DefaultDeflateCompatibilityWindow fixes this, too, eg:
DeflateCompressor compressor = new DeflateCompressor();
compressor.setCaching(false);
however I don't know if this is a safe change to make.
As described in the "external file attributes" section of the spec:
https://www.pkware.com/documents/APPNOTE/APPNOTE-6.3.2.TXT
Currently, the library doesn't even attempt to parse these so extraction on any
modern OS will almost certainly result in default (and possibly incorrect) file
system attributes. This is relatively minor, since the library isn't intended
to replace well-known command-line tools like "zip" and "jar", but it should
still be fixed.
Original issue reported on code.google.com by [email protected]
on 3 Aug 2014 at 8:44
Hello,
I'm an independent security researcher performing security research under the GitHub Security Lab Bug Bounty Program. I believe I may have found a security vulnerability in this project.
Please open a security advisory against this repository so we can privately discuss the details. This advisory can be opened by a user with admin permissions on this repository.
https://github.com/google/archive-patcher/security/advisories
Google truth imports unsafe and other unavailable apis on android.
Only test projects (And a single annotation in generator) rely on google truth.
Can be fixed by updating dependencies a little as in: PokeMMO@41b276a
Hi there, I'm getting the following error when attempting to generate a patch for a large archive (just under 2GB). I've tried to use the master and v2 branches - both fail. It looks like there is a hardcoded size limit in DivSuffixSorter.
How can I make a patch for a file this large?
Thanks for your help!
Exception in thread "main" java.lang.IllegalArgumentException: Input too large (1973952678 bytes)
at com.google.archivepatcher.generator.bsdiff.DivSuffixSorter.suffixSort(DivSuffixSorter.java:92)
at com.google.archivepatcher.generator.bsdiff.BsDiffPatchWriter.generatePatch(BsDiffPatchWriter.java:370)
at com.google.archivepatcher.generator.bsdiff.BsDiffPatchWriter.generatePatch(BsDiffPatchWriter.java:336)
at com.google.archivepatcher.generator.bsdiff.BsDiffDeltaGenerator.generateDelta(BsDiffDeltaGenerator.java:52)
at com.google.archivepatcher.generator.PatchWriter.writeDeltaEntry(PatchWriter.java:157)
at com.google.archivepatcher.generator.PatchWriter.writePatch(PatchWriter.java:123)
at com.google.archivepatcher.generator.FileByFileDeltaGenerator.generateDelta(FileByFileDeltaGenerator.java:120)
at com.google.archivepatcher.generator.DeltaGenerator.generateDelta(DeltaGenerator.java:38)
at com.google.archivepatcher.sample.SamplePatchGenerator.main(SamplePatchGenerator.java:43)
Hi thanks for the lib! I wonder whether this lib is ready to be used in production environment, or it is already deprecated (seems nobody is maintaining it...)? Thanks!
Hi I am not very familiar with java compilation. Thus I wonder how should I run the code in sample
dir? If I directly compile it, java complains that many classes are not defined. I also tried things like javac -cp archive-patcher-1.0.jar ./SamplePatchGenerator.java && java SamplePatchGenerator
(with jar downloaded and put in the right location), but still no luck. Thanks!
On Android 12 devices(Almost all of android 12 devices), I found in certain cases the file generated with the patch was different from the origin file;
env: android os version:android12,archive-patcher version:v1.1
my test files as flows:
old file:19onlyjar.zip
patch file:patch-onlyjar.zip
origin file:20onlyjar-ori.zip
how to reproduce:
1、unzip patch file first;
2、apply the patch with the following code:
` public static void applyPatch(File oldFile, File patchFile, File newFile, File tempDir) throws IOException {
if(!tempDir.exists()){
tempDir.mkdirs();
}
BufferedInputStream bufferedPatchIn = null;
BufferedOutputStream bufferedNewOut = null;
try{
FileByFileV1DeltaApplier applier = new FileByFileV1DeltaApplier(tempDir);
FileInputStream patchIn = new FileInputStream(patchFile);
bufferedPatchIn = new BufferedInputStream(patchIn);
FileOutputStream newOut = new FileOutputStream(newFile);
bufferedNewOut = new BufferedOutputStream(newOut);
applier.applyDelta(oldFile, bufferedPatchIn, bufferedNewOut);
bufferedNewOut.flush();
}finally {
if(bufferedPatchIn != null){
bufferedPatchIn.close();
}
if(bufferedPatchIn != null){
bufferedPatchIn.close();
}
}
}`
3、compare the md5 between the origin file and the generated file in step2
Hi,
I'm not very familiar with java and when I want to build the code on branch v2, I get the following error:
soheil@soheil-thinkpad:~/projects/github/archive-patcher$ gradle build
Starting a Gradle Daemon (subsequent builds will be faster)
FAILURE: Build failed with an exception.
* Where:
Build file '/home/soheil/projects/github/archive-patcher/applier/build.gradle' line: 9
* What went wrong:
A problem occurred evaluating project ':applier'.
> Could not find method annotationProcessor() for arguments [com.google.auto.value:auto-value:1.6.2] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 3s
Could anyone help me with how can I fix this error?
ps: I can build source code from the master branch but since there are lots of files that I need to create a patch for them daily, I really need a huge improvement on the algorithm's performance. I would really thankful if you would give me some tips on how to improve the algorithm's speed.
Thanks in advance.
This issue was automatically created by Allstar.
Security Policy Violation
Project is out of compliance with Binary Artifacts policy: binaries present in source code
Rule Description
Binary Artifacts are an increased security risk in your repository. Binary artifacts cannot be reviewed, allowing the introduction of possibly obsolete or maliciously subverted executables. For more information see the Security Scorecards Documentation for Binary Artifacts.
Remediation Steps
To remediate, remove the generated executable artifacts from the repository.
Artifacts Found
Additional Information
This policy is drawn from Security Scorecards, which is a tool that scores a project's adherence to security best practices. You may wish to run a Scorecards scan directly on this repository for more details.
Allstar has been installed on all Google managed GitHub orgs. Policies are gradually being rolled out and enforced by the GOSST and OSPO teams. Learn more at http://go/allstar
This issue will auto resolve when the policy is in compliance.
Issue created by Allstar. See https://github.com/ossf/allstar/ for more information. For questions specific to the repository, please contact the owner or maintainer.
Android o apk25,find crash zlib not compatible on this system.
new DefaultDeflateCompatibilityWindow().isCompatible() return false
This is a result of the following bug:
http://bugs.java.com/view_bug.do?bug_id=4715154
We already knew that the only way to force the JVM to munmap is to do an explicit GC() after nulling all references to the map obtained from the file channel in RandomAccessMmapObject (http://bugs.java.com/view_bug.do?bug_id=4469299), but this is worse. Not only is the mmap reference retained but in addition the open file handle prevents the deletion of the file itself, meaning that all bsdiff temp files stay around forever on win32. Even deleteOnExit() doesn't catch them. This is a serious problem because it means that the temp files will build up forever until they are manually purged, filling the host's disk eventually. As bsdiff needs to allocate 16x the size of the inputs, this is Very Bad (TM).
The only workaround here that I am aware of is to do a full gc() on Windows when closing a RandomAccessMmapObject, which is extremely heavyweight.
The README talks about the delta descriptor mentioning bsdiff, but omits the important fact that compression is not used in this version of bsdiff. That's really important, and we should update the docs to make this clear for anyone trying to write a compatible patch applier. By default bsdiff uses bzip2 compression, using ANY compression inside the patch itself will yield an incompatible patch.
For completeness, to help this item stand alone in search results: each delta within the patch is deliberately left uncompressed. This is so that an arbitrary compression algorithm can be applied to the entire patch, decoupling the compression technology from the patch generation and patch application technology. This allows file-by-file patch generators/consumers to take advantage of better compression technology as it comes along without any code changes inside the patch generator or patch applier. For example, you can trivially use bzip2, zstd, brotli, zopfli, lzma, etc as alternatives to deflate when storing and/or transmitting the patches to patch consumers.
The library should have more extensive test data generated with a variety of
tools. Offhand, some of the following things make sense as common use cases:
1. Self-extracting ZIP archive
2. Executable Java Archives (JARs)
3. Android package files (APKs)
Beyond this, there are several edge case permutations that should be added:
1. Corrupt ZIP
2. ZIP containing the EOCD marker bytes in a comment block (correct seeking
behavior should skip these bytes and find the "real" EOCD)
3. Archives with "opaque bits" (see issue 1)
4. Empty archives
5. Non-empty archives with empty resources inside
For correctness, these archives should not be generated using this library, but
rather with external tools such as "zip", "jar", and "apt". This will help
guarantee compatibility.
Original issue reported on code.google.com by [email protected]
on 31 Jul 2014 at 12:12
Can you package it to jar or aar, then push it to the maven central or jcenter?
isCompatible is giving false in Android R version. Is there any reason?
if (!DefaultDeflateCompatibilityWindow().isCompatible) {
Logger.W("Zlib not compatible on this system")
return false
}
Also can we bundle zlib with apkpatcher as a library and make not to use system zlib to avoid these kind of issues during upgrade?
As described in the "internal file attributes" section of the spec:
https://www.pkware.com/documents/APPNOTE/APPNOTE-6.3.2.TXT
These should be trivially supported, and take the form of 4-byte headers prior
to each "logical record". It is not clear from first glance what constitutes a
"logical record", but presumably each Part (e.g., DataDescriptor,
LocalFileEntry, FileData, etc...) is a "logical record".
Support for "dark bits" should fix the immediate concern, which is in
manipulating archives that have these fields (see issue 1).
Original issue reported on code.google.com by [email protected]
on 3 Aug 2014 at 8:30
Background: to read a zip-like archive, code generally starts by seeking
backwards from the end-of-file looking for the End Of Central Directory (EOCD)
marker bytes. Once this is located the central directory can be read in,
yielding a listing of all the file entries in the zip. At this point most
engines will begin processing one or more entries in the zip file.
There is no standard that defines what comes before the start of the first
"Local File" entry in the zip nor what comes after the End Of Central
Directory's entry's final byte. These sections can contain arbitrary data that
may be needed by some tools, although it seems rare to encounter these in
practice.
Empirically, all ZIP and APK files that I have run the tool against so far have
not had any such bits; this is known because the result of applying a patch to
such a file would produce incorrect results if there were any such "dark bits"
today (since they are not copied by the patching structure).
There is mention of such files "in the wild", e.g. executable JARs:
http://mesosphere.io/2013/12/07/executable-jars/
... and in older PKZIP-created stuff, there is apparently always a prefix of
the ASCII chars 'PK', potentially followed by a bunch of stuff specific to
whatever tool is intended to interpret it, e.g. PKLITE, PKSFX, and so on:
http://www.garykessler.net/library/file_sigs.html
This implies that the library needs a few modifications:
1. A new "OpaqueBits" (or similar) subclass of Part
2. The ability for such OpaqueBits to be present at the start and end of an
archive.
3. The ability to send these parts along in a patch.
Since such bits are by definition opaque, there's probably nothing we can do
special for them; running them through the configured delta provider seems the
only sensible thing to do.
Extending this thought further, it may also be the case that some archives
contain interstitial bits between entries. Again, this is undefined behavior;
even if the spec declared that there should be no such bytes, it is an
almost-certainty that every nontrivial ZIP implementation uses the central
directory to find all the offsets for all the entries, meaning that it should
be possible to inject extra bits between entries with no ill effects in most
cases.
The fix for this latter problem is to generalize the problem and identify any
and all gaps:
1. Gap between start of file and first local file entry.
2. Gap between the end of a file entry and start of the next file entry.
3. Gap between the final file entry and the start of the central directory.
4. Gap between the final bytes in the central directory and the first byte of
the End Of Central Directory record.
5. Gap between the final byte of the End Of Central Directory record and the
end of the file.
There's a hidden bonus to doing this, which is that it will automagically
enhance the library to support ZIP records for which it has no specific
support, since any such records would take the form of opaque bits by this
definition. These would correctly be included in the patch.
This should be a fairly straightforward change; all that is required is to
generate an offset-based linear ordering of all the entries and find their
gaps. Since the opaque bits have no discernible structure, they are just binary
blobs from the perspective of the library.
Original issue reported on code.google.com by [email protected]
on 31 Jul 2014 at 12:08
If the new archive contains two or more entries that BOTH require uncompression of THE SAME entry in the old archive, two uncompress instructions are generated in the patch stream for the same range. The patch applier expects ranges to be sorted in increasing order, so when it encounters the second range in the stream the offset that it specifies has already been processed and so the patch is treated as invalid.
The fix is to switch from a List to a Set in the PreDiffPlanner; if any entry in the new archive requires decompression of an entry in the old archive, then the old entry should be uncompressed and the instruction should be output exactly once. A new test needs to be added for this case as well.
This didn't come up before because it's a little weird to both clone a resource AND change its compression level at the same time when building a new archive, but it is a valid use case and it is currently broken.
Thanks for this repo, before which we use bsdiff while archive-diff works much better with zip files. The problem is that we have clients of both Android and iOS, and it is not a bad idea to do the same diff and patch jobs within both platforms.
However, I can not find any similar implementation with cpp/object-c. Could anyone offer a way? I am trying to translate the patching job with my poor cpp.
Getting above exception while using tar.gz file of size 81MB.
I tried changing the file permissions but it didn't help.
Is there a size limitation with current implementation? Any other leads are appreciable. Thanks.
StackTrace:
Exception in thread "main" java.util.zip.ZipException: EOCD record not found in last 32k of archive, giving up at com.google.archivepatcher.generator.MinimalZipArchive.listEntriesInternal(MinimalZipArchive.java:72) at com.google.archivepatcher.generator.MinimalZipArchive.listEntries(MinimalZipArchive.java:56) at com.google.archivepatcher.generator.PreDiffExecutor.generatePreDiffPlan(PreDiffExecutor.java:210) at com.google.archivepatcher.generator.PreDiffExecutor.prepareForDiffing(PreDiffExecutor.java:157) at com.google.archivepatcher.generator.FileByFileV1DeltaGenerator.generateDelta(FileByFileV1DeltaGenerator.java:81) at com.google.archivepatcher.sample.SamplePatchGenerator.main(SamplePatchGenerator.java:41)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.