55
66#include < filesystem>
77#include < format>
8+ #include < fstream>
89#include < iostream>
910
1011namespace fs = std::filesystem;
1112
1213namespace pkgfile {
1314
14- // static
15- std::unique_ptr<ArchiveConverter> ArchiveConverter::New (
16- const std::string& reponame, int fd_in, std::string base_filename_out,
17- int compress, int repo_chunk_bytes) {
18- const char * error;
19-
20- auto reader = ReadArchive::New (fd_in, &error);
21- if (reader == nullptr ) {
22- std::cerr << std::format (
23- " error: failed to create archive reader for {}: {}\n " , reponame, error);
24- return nullptr ;
15+ namespace {
16+
17+ std::pair<std::string_view, std::string_view> ParsePkgname (
18+ std::string_view entryname) {
19+ const auto pkgrel = entryname.rfind (' -' );
20+ if (pkgrel == entryname.npos ) {
21+ return {};
2522 }
2623
27- auto writer = WriteArchive::New (
28- MakeArchiveChunkFilename (base_filename_out, 0 , true ), compress, &error);
29- if (writer == nullptr ) {
30- std::cerr << std::format (" error: failed to open file for writing: {}: {}\n " ,
31- base_filename_out, error);
32- return nullptr ;
24+ const auto pkgver = entryname.substr (0 , pkgrel).rfind (' -' );
25+ if (pkgver == entryname.npos ) {
26+ return {};
3327 }
3428
35- return std::make_unique<ArchiveConverter>(
36- reponame, std::move (base_filename_out), compress, repo_chunk_bytes,
37- std::move (reader), std::move (writer));
29+ return {entryname.substr (0 , pkgver), entryname.substr (pkgver + 1 )};
3830}
3931
32+ } // namespace
33+
4034std::string ArchiveConverter::MakeArchiveChunkFilename (
4135 const std::string& base_filename, int chunk_number, bool tempfile) {
4236 return std::format (" {}.{:03d}{}" , base_filename, chunk_number,
4337 tempfile ? " ~" : " " );
4438}
4539
4640bool ArchiveConverter::NextArchiveChunk () {
47- if (!out_->Close ()) {
48- return false ;
49- }
50-
51- const char * error;
52-
53- auto writer = WriteArchive::New (
54- MakeArchiveChunkFilename (base_filename_out_, ++chunk_number_, true ),
55- compress_, &error);
56- if (writer == nullptr ) {
57- std::cerr << std::format (" error: failed to open file for writing: {}: {}\n " ,
58- base_filename_out_, error);
59- return false ;
60- }
41+ std::string chunk_name =
42+ MakeArchiveChunkFilename (base_filename_out_, chunk_number_++, true );
43+ cista::buf mmap{cista::mmap{chunk_name.c_str ()}};
44+ cista::serialize<cista::mode::NONE>(mmap, data_);
6145
62- out_ = std::move (writer );
46+ data_. clear ( );
6347
6448 return true ;
6549}
6650
67- int ArchiveConverter::WriteCpioEntry (archive_entry* ae,
68- const fs::path& entryname) {
69- pkgfile::ArchiveReader reader (in_->read_archive ());
51+ int ArchiveConverter::WriteMetaEntry (const fs::path& entryname) {
52+ ArchiveReader reader (in_->read_archive ());
7053 std::string_view line;
7154
7255 // discard the first line
7356 reader.GetLine (&line);
7457
75- std::string entry;
76- while (reader.GetLine (&line) == ARCHIVE_OK) {
77- // do the copy, with a slash prepended
78- std::format_to (std::back_inserter (entry), " /{}\n " , line);
58+ auto [name, version] = ParsePkgname (entryname.c_str ());
59+ if (name.empty ()) {
60+ return 0 ;
7961 }
8062
81- // adjust the entry size for removing the first line and adding slashes
82- archive_entry_set_size (ae, entry.size ());
83-
84- // inodes in cpio archives are dumb.
85- archive_entry_set_ino64 (ae, 0 );
86-
87- // store the metadata as simply $pkgname-$pkgver-$pkgrel
88- archive_entry_update_pathname_utf8 (ae, entryname.parent_path ().c_str ());
89-
90- if (archive_write_header (out_->write_archive (), ae) != ARCHIVE_OK) {
91- std::cerr << std::format (" error: failed to write entry header: {}/{}: {}\n " ,
92- reponame_, archive_entry_pathname (ae),
93- strerror (errno));
94- return -errno;
95- }
63+ auto & pkg = data_[name];
64+ pkg.version = version;
9665
97- if (archive_write_data (out_->write_archive (), entry.c_str (), entry.size ()) !=
98- static_cast <ssize_t >(entry.size ())) {
99- std::cerr << std::format (" error: failed to write entry: {}/{}: {}\n " ,
100- reponame_, archive_entry_pathname (ae),
101- strerror (errno));
102- return -errno;
66+ int bytesize = 0 ;
67+ while (reader.GetLine (&line) == ARCHIVE_OK) {
68+ // do the copy, with a slash prepended
69+ bytesize += pkg.files .emplace_back (std::format (" /{}" , line)).size ();
10370 }
10471
105- return entry. size () ;
72+ return bytesize ;
10673}
10774
10875bool ArchiveConverter::Finalize () {
109- in_->Close ();
110-
111- if (!out_->Close ()) {
112- return false ;
113- }
76+ NextArchiveChunk ();
11477
11578 struct stat st;
116- fstat (in_->fd (), &st);
79+ in_->Stat (&st);
80+ in_->Close ();
11781
11882 const struct timeval times[] = {
11983 {st.st_atim .tv_sec , 0 },
12084 {st.st_mtim .tv_sec , 0 },
12185 };
12286
123- for (int i = 0 ; i <= chunk_number_; ++i) {
87+ for (int i = 0 ; i < chunk_number_; ++i) {
12488 std::string path = MakeArchiveChunkFilename (base_filename_out_, i, true );
89+ std::string dest = MakeArchiveChunkFilename (base_filename_out_, i, false );
12590
12691 if (utimes (path.c_str (), times) < 0 ) {
12792 std::cerr << std::format (" warning: failed to set filetimes on {}: {}\n " ,
128- out_-> path () , strerror (errno));
93+ path, strerror (errno));
12994 }
13095
131- const fs::path dest = path.substr (0 , path.size () - 1 );
132-
13396 std::error_code ec;
13497 if (fs::rename (path, dest, ec); ec.value () != 0 ) {
13598 std::cerr << std::format (" error: renaming tmpfile to {} failed: {}\n " ,
136- dest. string () , ec.message ());
99+ dest, ec.message ());
137100 }
138101 }
139102
140- for (int i = chunk_number_ + 1 ;; ++i) {
103+ for (int i = chunk_number_;; ++i) {
141104 std::string path = MakeArchiveChunkFilename (base_filename_out_, i, false );
142105
143106 std::error_code ec;
@@ -162,17 +125,19 @@ bool ArchiveConverter::RewriteArchive() {
162125 chunk_size = 0 ;
163126 }
164127
165- fs::path entryname = archive_entry_pathname (ae);
128+ const fs::path entryname = archive_entry_pathname (ae);
166129
167130 // ignore everything but the /files metadata
168- if (entryname.filename () == " files" ) {
169- const int bytes_written = WriteCpioEntry (ae, entryname);
170- if (bytes_written < 0 ) {
171- return false ;
172- }
131+ if (entryname.filename () != " files" ) {
132+ continue ;
133+ }
173134
174- chunk_size += bytes_written;
135+ const int bytes_written = WriteMetaEntry (entryname.parent_path ());
136+ if (bytes_written < 0 ) {
137+ return false ;
175138 }
139+
140+ chunk_size += bytes_written;
176141 }
177142
178143 return Finalize ();
0 commit comments