Home | History | Annotate | Download | only in otautil
      1 /*
      2  * Copyright (C) 2016 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 "ZipUtil.h"
     18 
     19 #include <errno.h>
     20 #include <fcntl.h>
     21 #include <utime.h>
     22 
     23 #include <string>
     24 
     25 #include <android-base/logging.h>
     26 #include <android-base/unique_fd.h>
     27 #include <selinux/label.h>
     28 #include <selinux/selinux.h>
     29 #include <ziparchive/zip_archive.h>
     30 
     31 #include "DirUtil.h"
     32 
     33 static constexpr mode_t UNZIP_DIRMODE = 0755;
     34 static constexpr mode_t UNZIP_FILEMODE = 0644;
     35 
     36 bool ExtractPackageRecursive(ZipArchiveHandle zip, const std::string& zip_path,
     37                              const std::string& dest_path, const struct utimbuf* timestamp,
     38                              struct selabel_handle* sehnd) {
     39     if (!zip_path.empty() && zip_path[0] == '/') {
     40         LOG(ERROR) << "ExtractPackageRecursive(): zip_path must be a relative path " << zip_path;
     41         return false;
     42     }
     43     if (dest_path.empty() || dest_path[0] != '/') {
     44         LOG(ERROR) << "ExtractPackageRecursive(): dest_path must be an absolute path " << dest_path;
     45         return false;
     46     }
     47 
     48     void* cookie;
     49     std::string target_dir(dest_path);
     50     if (dest_path.back() != '/') {
     51         target_dir += '/';
     52     }
     53     std::string prefix_path(zip_path);
     54     if (!zip_path.empty() && zip_path.back() != '/') {
     55         prefix_path += '/';
     56     }
     57     const ZipString zip_prefix(prefix_path.c_str());
     58 
     59     int ret = StartIteration(zip, &cookie, &zip_prefix, nullptr);
     60     if (ret != 0) {
     61         LOG(ERROR) << "failed to start iterating zip entries.";
     62         return false;
     63     }
     64 
     65     std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
     66     ZipEntry entry;
     67     ZipString name;
     68     int extractCount = 0;
     69     while (Next(cookie, &entry, &name) == 0) {
     70         std::string entry_name(name.name, name.name + name.name_length);
     71         CHECK_LE(prefix_path.size(), entry_name.size());
     72         std::string path = target_dir + entry_name.substr(prefix_path.size());
     73         // Skip dir.
     74         if (path.back() == '/') {
     75             continue;
     76         }
     77         //TODO(b/31917448) handle the symlink.
     78 
     79         if (dirCreateHierarchy(path.c_str(), UNZIP_DIRMODE, timestamp, true, sehnd) != 0) {
     80             LOG(ERROR) << "failed to create dir for " << path;
     81             return false;
     82         }
     83 
     84         char *secontext = NULL;
     85         if (sehnd) {
     86             selabel_lookup(sehnd, &secontext, path.c_str(), UNZIP_FILEMODE);
     87             setfscreatecon(secontext);
     88         }
     89         android::base::unique_fd fd(open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC, UNZIP_FILEMODE));
     90         if (fd == -1) {
     91             PLOG(ERROR) << "Can't create target file \"" << path << "\"";
     92             return false;
     93         }
     94         if (secontext) {
     95             freecon(secontext);
     96             setfscreatecon(NULL);
     97         }
     98 
     99         int err = ExtractEntryToFile(zip, &entry, fd);
    100         if (err != 0) {
    101             LOG(ERROR) << "Error extracting \"" << path << "\" : " << ErrorCodeString(err);
    102             return false;
    103         }
    104 
    105         if (fsync(fd) != 0) {
    106             PLOG(ERROR) << "Error syncing file descriptor when extracting \"" << path << "\"";
    107             return false;
    108         }
    109 
    110         if (timestamp != nullptr && utime(path.c_str(), timestamp)) {
    111             PLOG(ERROR) << "Error touching \"" << path << "\"";
    112             return false;
    113         }
    114 
    115         LOG(INFO) << "Extracted file \"" << path << "\"";
    116         ++extractCount;
    117     }
    118 
    119     LOG(INFO) << "Extracted " << extractCount << " file(s)";
    120     return true;
    121 }
    122