Skip to content

Commit c8edcaf

Browse files
committed
Separate readable_zip_source.[cc,h]
Bug: b/458815945
1 parent 8968d06 commit c8edcaf

File tree

13 files changed

+337
-234
lines changed

13 files changed

+337
-234
lines changed

base/cvd/cuttlefish/host/libs/zip/BUILD.bazel

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ cf_cc_library(
168168
hdrs = ["zip_copy.h"],
169169
deps = [
170170
"//cuttlefish/common/libs/utils:result",
171-
"//cuttlefish/host/libs/zip/libzip_cc:source",
171+
"//cuttlefish/host/libs/zip/libzip_cc:readable_source",
172172
"//cuttlefish/host/libs/zip/libzip_cc:writable_source",
173173
],
174174
)
@@ -197,8 +197,9 @@ cf_cc_library(
197197
"//cuttlefish/common/libs/utils:result",
198198
"//cuttlefish/host/libs/zip:zip_copy",
199199
"//cuttlefish/host/libs/zip/libzip_cc:archive",
200-
"//cuttlefish/host/libs/zip/libzip_cc:source",
200+
"//cuttlefish/host/libs/zip/libzip_cc:readable_source",
201201
"//cuttlefish/host/libs/zip/libzip_cc:stat",
202+
"//cuttlefish/host/libs/zip/libzip_cc:writable_source",
202203
],
203204
)
204205

@@ -209,6 +210,7 @@ cf_cc_library(
209210
deps = [
210211
"//cuttlefish/common/libs/utils:result",
211212
"//cuttlefish/host/libs/zip/libzip_cc:archive",
212-
"//cuttlefish/host/libs/zip/libzip_cc:source",
213+
"//cuttlefish/host/libs/zip/libzip_cc:readable_source",
214+
"//cuttlefish/host/libs/zip/libzip_cc:writable_source",
213215
],
214216
)

base/cvd/cuttlefish/host/libs/zip/libzip_cc/BUILD.bazel

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ cf_cc_library(
1717
"//cuttlefish/common/libs/utils:result",
1818
"//cuttlefish/host/libs/zip/libzip_cc:error",
1919
"//cuttlefish/host/libs/zip/libzip_cc:managed",
20+
"//cuttlefish/host/libs/zip/libzip_cc:readable_source",
2021
"//cuttlefish/host/libs/zip/libzip_cc:source",
2122
"//cuttlefish/host/libs/zip/libzip_cc:writable_source",
2223
"@libzip",
@@ -48,6 +49,24 @@ cf_cc_library(
4849
deps = ["@libzip"],
4950
)
5051

52+
cf_cc_library(
53+
name = "readable_source",
54+
srcs = ["readable_source.cc"],
55+
hdrs = ["readable_source.h"],
56+
features = ["-layering_check"], # libzip
57+
linkopts = ["-llzma"], # libzip
58+
linkstatic = True, # libzip
59+
deps = [
60+
"//cuttlefish/common/libs/utils:result",
61+
"//cuttlefish/host/libs/zip/libzip_cc:error",
62+
"//cuttlefish/host/libs/zip/libzip_cc:managed",
63+
"//cuttlefish/host/libs/zip/libzip_cc:source_callback",
64+
"//cuttlefish/host/libs/zip/libzip_cc:stat",
65+
"@libzip",
66+
"@zlib",
67+
],
68+
)
69+
5170
cf_cc_library(
5271
name = "stat",
5372
hdrs = ["stat.h"],
@@ -64,8 +83,8 @@ cf_cc_library(
6483
"//cuttlefish/common/libs/utils:result",
6584
"//cuttlefish/host/libs/zip/libzip_cc:error",
6685
"//cuttlefish/host/libs/zip/libzip_cc:managed",
86+
"//cuttlefish/host/libs/zip/libzip_cc:readable_source",
6787
"//cuttlefish/host/libs/zip/libzip_cc:source_callback",
68-
"//cuttlefish/host/libs/zip/libzip_cc:stat",
6988
"@libzip",
7089
"@zlib",
7190
],

base/cvd/cuttlefish/host/libs/zip/libzip_cc/archive.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "cuttlefish/common/libs/utils/result.h"
2828
#include "cuttlefish/host/libs/zip/libzip_cc/error.h"
2929
#include "cuttlefish/host/libs/zip/libzip_cc/managed.h"
30+
#include "cuttlefish/host/libs/zip/libzip_cc/readable_source.h"
3031
#include "cuttlefish/host/libs/zip/libzip_cc/source.h"
3132
#include "cuttlefish/host/libs/zip/libzip_cc/writable_source.h"
3233

base/cvd/cuttlefish/host/libs/zip/libzip_cc/archive.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "cuttlefish/common/libs/utils/result.h"
2424
#include "cuttlefish/host/libs/zip/libzip_cc/managed.h"
25+
#include "cuttlefish/host/libs/zip/libzip_cc/readable_source.h"
2526
#include "cuttlefish/host/libs/zip/libzip_cc/source.h"
2627
#include "cuttlefish/host/libs/zip/libzip_cc/writable_source.h"
2728

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
//
2+
// Copyright (C) 2025 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+
#include "cuttlefish/host/libs/zip/libzip_cc/readable_source.h"
17+
18+
#include <errno.h>
19+
#include <stddef.h>
20+
#include <stdint.h>
21+
#include <stdio.h>
22+
23+
#include <memory>
24+
#include <optional>
25+
#include <string>
26+
#include <utility>
27+
28+
#include "zip.h"
29+
30+
#include "cuttlefish/common/libs/utils/result.h"
31+
#include "cuttlefish/host/libs/zip/libzip_cc/error.h"
32+
#include "cuttlefish/host/libs/zip/libzip_cc/managed.h"
33+
#include "cuttlefish/host/libs/zip/libzip_cc/source_callback.h"
34+
#include "cuttlefish/host/libs/zip/libzip_cc/stat.h"
35+
36+
namespace cuttlefish {
37+
namespace {
38+
39+
struct ReadableCallbackSource {
40+
ReadableCallbackSource(std::unique_ptr<ReadableZipSourceCallback> callbacks)
41+
: callbacks_(std::move(callbacks)), error_(NewZipError()) {}
42+
43+
std::unique_ptr<ReadableZipSourceCallback> callbacks_;
44+
ManagedZipError error_;
45+
};
46+
47+
// https://libzip.org/documentation/zip_source_function.html
48+
int64_t ReadableZipSourceCallbackFn(void* userdata, void* data, uint64_t len,
49+
zip_source_cmd_t cmd) {
50+
ReadableCallbackSource* source =
51+
reinterpret_cast<ReadableCallbackSource*>(userdata);
52+
if (cmd == ZIP_SOURCE_FREE) {
53+
delete source;
54+
return 0;
55+
}
56+
return HandleCallback(*source->callbacks_, source->error_.get(), data, len,
57+
cmd);
58+
}
59+
60+
std::optional<ZipCompression> CompressionFromRaw(uint16_t method) {
61+
switch (method) {
62+
case ZIP_CM_DEFAULT:
63+
return ZipCompression::kDefault;
64+
case ZIP_CM_STORE:
65+
return ZipCompression::kStore;
66+
case ZIP_CM_BZIP2:
67+
return ZipCompression::kBzip2;
68+
case ZIP_CM_DEFLATE:
69+
return ZipCompression::kDeflate;
70+
case ZIP_CM_XZ:
71+
return ZipCompression::kXz;
72+
case ZIP_CM_ZSTD:
73+
return ZipCompression::kZstd;
74+
default:
75+
return {};
76+
}
77+
}
78+
79+
} // namespace
80+
81+
int64_t HandleCallback(ReadableZipSourceCallback& callbacks, zip_error_t* error,
82+
void* data, uint64_t len, zip_source_cmd_t cmd) {
83+
switch (cmd) {
84+
case ZIP_SOURCE_CLOSE: {
85+
bool callback_res = callbacks.Close();
86+
if (!callback_res) {
87+
zip_error_set(error, ZIP_ER_CLOSE, errno);
88+
}
89+
return callback_res ? 0 : -1;
90+
}
91+
case ZIP_SOURCE_ERROR:
92+
return zip_error_to_data(error, data, len);
93+
case ZIP_SOURCE_OPEN: {
94+
bool callback_res = callbacks.Open();
95+
if (!callback_res) {
96+
zip_error_set(error, ZIP_ER_OPEN, errno);
97+
}
98+
return callback_res ? 0 : -1;
99+
}
100+
case ZIP_SOURCE_READ: {
101+
int64_t callback_res = callbacks.Read(reinterpret_cast<char*>(data), len);
102+
if (callback_res < 0) {
103+
zip_error_set(error, ZIP_ER_READ, errno);
104+
}
105+
return callback_res;
106+
}
107+
case ZIP_SOURCE_STAT: {
108+
zip_stat_t* stat_out = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, len, error);
109+
zip_stat_init(stat_out);
110+
stat_out->valid = ZIP_STAT_SIZE;
111+
stat_out->size = callbacks.Size();
112+
return 0;
113+
}
114+
case ZIP_SOURCE_SUPPORTS:
115+
return zip_source_make_command_bitmap(
116+
ZIP_SOURCE_CLOSE, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_OPEN,
117+
ZIP_SOURCE_READ, ZIP_SOURCE_STAT, ZIP_SOURCE_SUPPORTS, -1);
118+
default:
119+
zip_error_set(error, ZIP_ER_OPNOTSUPP, EINVAL);
120+
return -1;
121+
}
122+
}
123+
124+
Result<ReadableZipSource> ReadableZipSource::FromCallbacks(
125+
std::unique_ptr<ReadableZipSourceCallback> callbacks) {
126+
CF_EXPECT(callbacks.get());
127+
128+
std::unique_ptr<ReadableCallbackSource> wrapped_source =
129+
std::make_unique<ReadableCallbackSource>(std::move(callbacks));
130+
131+
ManagedZipError error = NewZipError();
132+
ManagedZipSource source(zip_source_function_create(
133+
ReadableZipSourceCallbackFn, wrapped_source.release(), error.get()));
134+
135+
CF_EXPECT(source.get(), ZipErrorString(error.get()));
136+
137+
return ReadableZipSource(std::move(source));
138+
}
139+
140+
// These have to be defined in the `.cc` file to avoid linker errors because of
141+
// bazel weirdness around cmake files.
142+
ReadableZipSource::ReadableZipSource(ReadableZipSource&&) = default;
143+
ReadableZipSource::~ReadableZipSource() = default;
144+
ReadableZipSource& ReadableZipSource::operator=(ReadableZipSource&&) = default;
145+
146+
Result<ZipStat> ReadableZipSource::Stat() {
147+
zip_source_t* raw_source = CF_EXPECT(raw_.get());
148+
149+
zip_stat_t raw_stat;
150+
zip_stat_init(&raw_stat);
151+
152+
CF_EXPECT_EQ(zip_source_stat(raw_source, &raw_stat), 0,
153+
ZipErrorString(raw_source));
154+
155+
ZipStat ret;
156+
if (raw_stat.valid & ZIP_STAT_NAME) {
157+
ret.name = std::string(raw_stat.name);
158+
}
159+
if (raw_stat.valid & ZIP_STAT_INDEX) {
160+
ret.index = raw_stat.index;
161+
}
162+
if (raw_stat.valid & ZIP_STAT_SIZE) {
163+
ret.size = raw_stat.size;
164+
}
165+
if (raw_stat.valid & ZIP_STAT_COMP_SIZE) {
166+
ret.compressed_size = raw_stat.comp_size;
167+
}
168+
if (raw_stat.valid & ZIP_STAT_COMP_METHOD) {
169+
ret.compression_method = CompressionFromRaw(raw_stat.comp_method);
170+
}
171+
return ret;
172+
}
173+
174+
Result<ZipSourceReader> ReadableZipSource::Reader() {
175+
zip_source_t* raw_source = CF_EXPECT(raw_.get());
176+
177+
CF_EXPECT_EQ(zip_source_open(raw_source), 0, ZipErrorString(raw_source));
178+
179+
return ZipSourceReader(this);
180+
}
181+
182+
ReadableZipSource::ReadableZipSource(ManagedZipSource raw)
183+
: raw_(std::move(raw)) {}
184+
185+
ZipSourceReader::ZipSourceReader(ReadableZipSource* source) : source_(source) {}
186+
187+
ZipSourceReader::ZipSourceReader(ZipSourceReader&& other)
188+
: source_(other.source_) {
189+
other.source_ = nullptr;
190+
}
191+
192+
ZipSourceReader& ZipSourceReader::operator=(ZipSourceReader&& other) {
193+
source_ = other.source_;
194+
other.source_ = nullptr;
195+
return *this;
196+
}
197+
198+
ZipSourceReader::~ZipSourceReader() {
199+
if (source_ && source_->raw_) {
200+
zip_source_close(source_->raw_.get());
201+
}
202+
}
203+
204+
Result<uint64_t> ZipSourceReader::Read(void* data, uint64_t length) {
205+
CF_EXPECT_NE(source_, nullptr);
206+
zip_source_t* raw_source = CF_EXPECT(source_->raw_.get());
207+
208+
int64_t read_res = zip_source_read(raw_source, data, length);
209+
210+
CF_EXPECTF(read_res >= 0, "Read failed: '{}'", ZipErrorString(raw_source));
211+
212+
return read_res;
213+
}
214+
215+
} // namespace cuttlefish
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//
2+
// Copyright (C) 2025 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+
#pragma once
17+
18+
#include <stddef.h>
19+
#include <stdint.h>
20+
21+
#include <memory>
22+
#include <string>
23+
24+
#include "zip.h"
25+
26+
#include "cuttlefish/common/libs/utils/result.h"
27+
#include "cuttlefish/host/libs/zip/libzip_cc/managed.h"
28+
#include "cuttlefish/host/libs/zip/libzip_cc/source_callback.h"
29+
#include "cuttlefish/host/libs/zip/libzip_cc/stat.h"
30+
31+
namespace cuttlefish {
32+
33+
int64_t HandleCallback(ReadableZipSourceCallback& callbacks, zip_error_t* error,
34+
void* data, uint64_t len, zip_source_cmd_t cmd);
35+
36+
class ReadableZipSource {
37+
public:
38+
friend class ReadableZip;
39+
friend class WritableZip;
40+
friend class ZipSourceReader;
41+
friend class SeekingZipSourceReader;
42+
friend class ZipSourceWriter;
43+
44+
static Result<ReadableZipSource> FromCallbacks(
45+
std::unique_ptr<ReadableZipSourceCallback>);
46+
47+
// Can be safely called with a subclass type.
48+
ReadableZipSource(ReadableZipSource&&);
49+
virtual ~ReadableZipSource();
50+
// Can be safely called with a subclass type.
51+
ReadableZipSource& operator=(ReadableZipSource&&);
52+
53+
Result<ZipStat> Stat();
54+
55+
/* Returns a RAII instance that puts this instance in an "open for reading"
56+
* state. Can fail. Should not outlive this instance. */
57+
Result<class ZipSourceReader> Reader();
58+
59+
protected:
60+
ManagedZipSource raw_;
61+
62+
ReadableZipSource(ManagedZipSource);
63+
};
64+
65+
/* A `ReadableZipSource` in an "open for reading" state. */
66+
class ZipSourceReader {
67+
public:
68+
friend class ReadableZipSource;
69+
friend class SeekingZipSourceReader;
70+
71+
ZipSourceReader(ZipSourceReader&&);
72+
virtual ~ZipSourceReader();
73+
ZipSourceReader& operator=(ZipSourceReader&&);
74+
75+
/* Returns a failed Result on error, or a successful result with bytes read or
76+
* 0 on EOF. */
77+
Result<uint64_t> Read(void* data, uint64_t length);
78+
79+
private:
80+
ZipSourceReader(ReadableZipSource*);
81+
82+
ReadableZipSource* source_;
83+
};
84+
85+
} // namespace cuttlefish

0 commit comments

Comments
 (0)