Home | History | Annotate | Download | only in libs
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <errno.h>
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 
     21 #include <algorithm>
     22 #include <string>
     23 #include <vector>
     24 
     25 #include <ziparchive/zip_archive.h>
     26 #include <ziparchive/zip_archive_stream_entry.h>
     27 #include <ziparchive/zip_writer.h>
     28 
     29 static void usage() {
     30   fprintf(stderr, "usage: bionic_tests_zipalign ALIGNMENT INPUT_ZIP_FILE OUTPUT_ZIP_FILE\n");
     31   fprintf(stderr, "  ALIGNMENT:\n");
     32   fprintf(stderr, "    The new alignment of all entries in the new zip file.\n");
     33   fprintf(stderr, "  INPUT_ZIP_FILE:\n");
     34   fprintf(stderr, "    The input zip file that will be read but left unmodified.\n");
     35   fprintf(stderr, "  OUTPUT_ZIP_FILE:\n");
     36   fprintf(stderr, "    The output zip file that will be created from the input file.\n");
     37 }
     38 
     39 typedef std::pair<ZipEntry*, ZipString*> ZipData;
     40 
     41 static bool GetEntries(ZipArchiveHandle handle, std::vector<ZipData>* entries) {
     42   void* cookie;
     43   int32_t return_value = StartIteration(handle, &cookie, nullptr, nullptr);
     44   if (return_value != 0) {
     45     fprintf(stderr, "Unable to iterate over entries: %s\n", ErrorCodeString(return_value));
     46     return false;
     47   }
     48 
     49   ZipEntry entry;
     50   ZipString name;
     51   while ((return_value = Next(cookie, &entry, &name)) == 0) {
     52     entries->push_back(std::make_pair(new ZipEntry(entry), new ZipString(name)));
     53   }
     54   if (return_value != -1) {
     55     fprintf(stderr, "Error while iterating over zip entries: %s\n", ErrorCodeString(return_value));
     56   } else {
     57     // Sort by offset.
     58     std::sort(entries->begin(), entries->end(),
     59               [](ZipData a, ZipData b) { return a.first->offset < b.first->offset; });
     60   }
     61 
     62   EndIteration(cookie);
     63   return return_value == -1;
     64 }
     65 
     66 static bool CreateAlignedZip(ZipArchiveHandle& handle, FILE* zip_dst, uint32_t alignment) {
     67   std::vector<ZipData> entries;
     68   // We will not free the memory created in entries since the program
     69   // terminates right after this function is called.
     70   if (!GetEntries(handle, &entries)) {
     71     return false;
     72   }
     73 
     74   ZipWriter writer(zip_dst);
     75 
     76   int32_t error;
     77   for (auto& entry : entries) {
     78     ZipEntry* zip_entry = entry.first;
     79     ZipString* zip_str = entry.second;
     80 
     81     size_t flags = 0;
     82     if ((zip_entry->method & kCompressDeflated) != 0) {
     83       flags |= ZipWriter::kCompress;
     84     }
     85     std::string zip_name(reinterpret_cast<const char*>(zip_str->name), zip_str->name_length);
     86     error = writer.StartAlignedEntry(zip_name.c_str(), flags, alignment);
     87     if (error != 0) {
     88       fprintf(stderr, "StartAlignedEntry failed: %s\n", ZipWriter::ErrorCodeString(error));
     89       return false;
     90     }
     91     std::unique_ptr<ZipArchiveStreamEntry> stream(
     92         ZipArchiveStreamEntry::Create(handle, *zip_entry));
     93     const std::vector<uint8_t>* data;
     94     while ((data = stream->Read()) != nullptr) {
     95       error = writer.WriteBytes(data->data(), data->size());
     96       if (error != 0) {
     97         fprintf(stderr, "WriteBytes failed: %s\n", ZipWriter::ErrorCodeString(error));
     98         return false;
     99       }
    100     }
    101     if (!stream->Verify()) {
    102       fprintf(stderr, "Failed to verify zip stream writer entry.\n");
    103       return false;
    104     }
    105     error = writer.FinishEntry();
    106     if (error != 0) {
    107       fprintf(stderr, "FinishEntry failed: %s\n", ZipWriter::ErrorCodeString(error));
    108     }
    109   }
    110 
    111   error = writer.Finish();
    112   if (error != 0) {
    113     fprintf(stderr, "Finish failed: %s\n", ZipWriter::ErrorCodeString(error));
    114     return false;
    115   }
    116   return true;
    117 }
    118 
    119 int main(int argc, char* argv[]) {
    120   if (argc != 4) {
    121     usage();
    122     return 1;
    123   }
    124 
    125   char* end;
    126   unsigned long int alignment = strtoul(argv[1], &end, 10);
    127   if ((alignment == ULONG_MAX && errno == ERANGE) || *end != '\0') {
    128     fprintf(stderr, "ALIGNMENT value is not a valid number: %s\n", argv[1]);
    129     usage();
    130     return 1;
    131   }
    132   if (((alignment - 1) & alignment) != 0) {
    133     fprintf(stderr, "ALIGNMENT value is not a power of 2: %s\n", argv[1]);
    134     return 1;
    135   }
    136 
    137   ZipArchiveHandle handle;
    138 
    139   int32_t return_value = OpenArchive(argv[2], &handle);
    140   if (return_value != 0) {
    141     CloseArchive(handle);
    142     fprintf(stderr, "Unable to open '%s': %s\n", argv[2], ErrorCodeString(return_value));
    143     return false;
    144   }
    145 
    146   FILE* zip_dst = fopen(argv[3], "we");
    147   if (zip_dst == nullptr) {
    148     fprintf(stderr, "Unable to create '%s': %s\n", argv[3], strerror(errno));
    149     return 1;
    150   }
    151 
    152   bool success = CreateAlignedZip(handle, zip_dst, static_cast<uint32_t>(alignment));
    153 
    154   CloseArchive(handle);
    155   fclose(zip_dst);
    156 
    157   return success ? 0 : 1;
    158 }
    159