1 /*
2  * Copyright (C) 2008 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 #pragma once
18 
19 #include <ziparchive/zip_archive.h>
20 
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 
25 #include <memory>
26 #include <utility>
27 #include <vector>
28 
29 #include "android-base/macros.h"
30 #include "android-base/mapped_file.h"
31 #include "android-base/memory.h"
32 #include "zip_cd_entry_map.h"
33 #include "zip_error.h"
34 
35 class MappedZipFile {
36  public:
MappedZipFile(const int fd)37   explicit MappedZipFile(const int fd)
38       : has_fd_(true), fd_(fd), fd_offset_(0), base_ptr_(nullptr), data_length_(-1) {}
39 
MappedZipFile(const int fd,off64_t length,off64_t offset)40   explicit MappedZipFile(const int fd, off64_t length, off64_t offset)
41       : has_fd_(true), fd_(fd), fd_offset_(offset), base_ptr_(nullptr), data_length_(length) {}
42 
MappedZipFile(const void * address,size_t length)43   explicit MappedZipFile(const void* address, size_t length)
44       : has_fd_(false), fd_(-1), fd_offset_(0), base_ptr_(address),
45         data_length_(static_cast<off64_t>(length)) {}
46 
HasFd()47   bool HasFd() const { return has_fd_; }
48 
49   int GetFileDescriptor() const;
50 
51   const void* GetBasePtr() const;
52 
53   off64_t GetFileOffset() const;
54 
55   off64_t GetFileLength() const;
56 
57   bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const;
58 
59  private:
60   // If has_fd_ is true, fd is valid and we'll read contents of a zip archive
61   // from the file. Otherwise, we're opening the archive from a memory mapped
62   // file. In that case, base_ptr_ points to the start of the memory region and
63   // data_length_ defines the file length.
64   const bool has_fd_;
65 
66   const int fd_;
67   const off64_t fd_offset_;
68 
69   const void* const base_ptr_;
70   mutable off64_t data_length_;
71 };
72 
73 class CentralDirectory {
74  public:
CentralDirectory(void)75   CentralDirectory(void) : base_ptr_(nullptr), length_(0) {}
76 
GetBasePtr()77   const uint8_t* GetBasePtr() const { return base_ptr_; }
78 
GetMapLength()79   size_t GetMapLength() const { return length_; }
80 
81   void Initialize(const void* map_base_ptr, off64_t cd_start_offset, size_t cd_size);
82 
83  private:
84   const uint8_t* base_ptr_;
85   size_t length_;
86 };
87 
88 struct ZipArchive {
89   // open Zip archive
90   mutable MappedZipFile mapped_zip;
91   const bool close_file;
92 
93   // mapped central directory area
94   off64_t directory_offset;
95   CentralDirectory central_directory;
96   std::unique_ptr<android::base::MappedFile> directory_map;
97 
98   // number of entries in the Zip archive
99   uint64_t num_entries;
100   std::unique_ptr<CdEntryMapInterface> cd_entry_map;
101 
102   ZipArchive(MappedZipFile&& map, bool assume_ownership);
103   ZipArchive(const void* address, size_t length);
104   ~ZipArchive();
105 
106   bool InitializeCentralDirectory(off64_t cd_start_offset, size_t cd_size);
107 };
108 
109 // Reads the unaligned data of type |T| and auto increment the offset.
110 template <typename T>
ConsumeUnaligned(uint8_t ** address)111 static T ConsumeUnaligned(uint8_t** address) {
112   auto ret = android::base::get_unaligned<T>(*address);
113   *address += sizeof(T);
114   return ret;
115 }
116 
117 // Writes the unaligned data of type |T| and auto increment the offset.
118 template <typename T>
EmitUnaligned(uint8_t ** address,T data)119 void EmitUnaligned(uint8_t** address, T data) {
120   android::base::put_unaligned<T>(*address, data);
121   *address += sizeof(T);
122 }
123