mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 18:18:12 +00:00
LibArchive: Add support for modification time and date
This commit is contained in:
parent
361df6eff8
commit
0ce1c52577
4 changed files with 59 additions and 8 deletions
|
@ -90,6 +90,8 @@ ErrorOr<bool> Zip::for_each_member(Function<IterationDecision(ZipMember const&)>
|
||||||
member.compression_method = central_directory_record.compression_method;
|
member.compression_method = central_directory_record.compression_method;
|
||||||
member.uncompressed_size = central_directory_record.uncompressed_size;
|
member.uncompressed_size = central_directory_record.uncompressed_size;
|
||||||
member.crc32 = central_directory_record.crc32;
|
member.crc32 = central_directory_record.crc32;
|
||||||
|
member.modification_time = central_directory_record.modification_time;
|
||||||
|
member.modification_date = central_directory_record.modification_date;
|
||||||
member.is_directory = central_directory_record.external_attributes & zip_directory_external_attribute || member.name.bytes_as_string_view().ends_with('/'); // FIXME: better directory detection
|
member.is_directory = central_directory_record.external_attributes & zip_directory_external_attribute || member.name.bytes_as_string_view().ends_with('/'); // FIXME: better directory detection
|
||||||
|
|
||||||
if (callback(member) == IterationDecision::Break)
|
if (callback(member) == IterationDecision::Break)
|
||||||
|
@ -122,8 +124,8 @@ ErrorOr<void> ZipOutputStream::add_member(ZipMember const& member)
|
||||||
.minimum_version = minimum_version_needed(member.compression_method),
|
.minimum_version = minimum_version_needed(member.compression_method),
|
||||||
.general_purpose_flags = { .flags = 0 },
|
.general_purpose_flags = { .flags = 0 },
|
||||||
.compression_method = static_cast<u16>(member.compression_method),
|
.compression_method = static_cast<u16>(member.compression_method),
|
||||||
.modification_time = 0, // TODO: support modification time
|
.modification_time = member.modification_time,
|
||||||
.modification_date = 0,
|
.modification_date = member.modification_date,
|
||||||
.crc32 = member.crc32,
|
.crc32 = member.crc32,
|
||||||
.compressed_size = static_cast<u32>(member.compressed_data.size()),
|
.compressed_size = static_cast<u32>(member.compressed_data.size()),
|
||||||
.uncompressed_size = member.uncompressed_size,
|
.uncompressed_size = member.uncompressed_size,
|
||||||
|
@ -150,8 +152,8 @@ ErrorOr<void> ZipOutputStream::finish()
|
||||||
.minimum_version = zip_version,
|
.minimum_version = zip_version,
|
||||||
.general_purpose_flags = { .flags = 0 },
|
.general_purpose_flags = { .flags = 0 },
|
||||||
.compression_method = member.compression_method,
|
.compression_method = member.compression_method,
|
||||||
.modification_time = 0, // TODO: support modification time
|
.modification_time = member.modification_time,
|
||||||
.modification_date = 0,
|
.modification_date = member.modification_date,
|
||||||
.crc32 = member.crc32,
|
.crc32 = member.crc32,
|
||||||
.compressed_size = static_cast<u32>(member.compressed_data.size()),
|
.compressed_size = static_cast<u32>(member.compressed_data.size()),
|
||||||
.uncompressed_size = member.uncompressed_size,
|
.uncompressed_size = member.uncompressed_size,
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Array.h>
|
#include <AK/Array.h>
|
||||||
|
#include <AK/DOSPackedTime.h>
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <AK/IterationDecision.h>
|
#include <AK/IterationDecision.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
|
@ -112,8 +113,8 @@ struct [[gnu::packed]] CentralDirectoryRecord {
|
||||||
u16 minimum_version;
|
u16 minimum_version;
|
||||||
ZipGeneralPurposeFlags general_purpose_flags;
|
ZipGeneralPurposeFlags general_purpose_flags;
|
||||||
ZipCompressionMethod compression_method;
|
ZipCompressionMethod compression_method;
|
||||||
u16 modification_time;
|
DOSPackedTime modification_time;
|
||||||
u16 modification_date;
|
DOSPackedDate modification_date;
|
||||||
u32 crc32;
|
u32 crc32;
|
||||||
u32 compressed_size;
|
u32 compressed_size;
|
||||||
u32 uncompressed_size;
|
u32 uncompressed_size;
|
||||||
|
@ -186,8 +187,8 @@ struct [[gnu::packed]] LocalFileHeader {
|
||||||
u16 minimum_version;
|
u16 minimum_version;
|
||||||
ZipGeneralPurposeFlags general_purpose_flags;
|
ZipGeneralPurposeFlags general_purpose_flags;
|
||||||
u16 compression_method;
|
u16 compression_method;
|
||||||
u16 modification_time;
|
DOSPackedTime modification_time;
|
||||||
u16 modification_date;
|
DOSPackedDate modification_date;
|
||||||
u32 crc32;
|
u32 crc32;
|
||||||
u32 compressed_size;
|
u32 compressed_size;
|
||||||
u32 uncompressed_size;
|
u32 uncompressed_size;
|
||||||
|
@ -244,6 +245,8 @@ struct ZipMember {
|
||||||
u32 uncompressed_size;
|
u32 uncompressed_size;
|
||||||
u32 crc32;
|
u32 crc32;
|
||||||
bool is_directory;
|
bool is_directory;
|
||||||
|
DOSPackedTime modification_time;
|
||||||
|
DOSPackedDate modification_date;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Zip {
|
class Zip {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Assertions.h>
|
#include <AK/Assertions.h>
|
||||||
|
#include <AK/DOSPackedTime.h>
|
||||||
#include <AK/NumberFormat.h>
|
#include <AK/NumberFormat.h>
|
||||||
#include <AK/StringUtils.h>
|
#include <AK/StringUtils.h>
|
||||||
#include <LibArchive/Zip.h>
|
#include <LibArchive/Zip.h>
|
||||||
|
@ -17,6 +18,18 @@
|
||||||
#include <LibCrypto/Checksum/CRC32.h>
|
#include <LibCrypto/Checksum/CRC32.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
static ErrorOr<void> adjust_modification_time(Archive::ZipMember const& zip_member)
|
||||||
|
{
|
||||||
|
auto time = time_from_packed_dos(zip_member.modification_date, zip_member.modification_time);
|
||||||
|
auto seconds = static_cast<time_t>(time.to_seconds());
|
||||||
|
struct utimbuf buf {
|
||||||
|
.actime = seconds,
|
||||||
|
.modtime = seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
return Core::System::utime(zip_member.name, buf);
|
||||||
|
}
|
||||||
|
|
||||||
static bool unpack_zip_member(Archive::ZipMember zip_member, bool quiet)
|
static bool unpack_zip_member(Archive::ZipMember zip_member, bool quiet)
|
||||||
{
|
{
|
||||||
if (zip_member.is_directory) {
|
if (zip_member.is_directory) {
|
||||||
|
@ -69,6 +82,11 @@ static bool unpack_zip_member(Archive::ZipMember zip_member, bool quiet)
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (adjust_modification_time(zip_member).is_error()) {
|
||||||
|
warnln("Failed setting modification_time for file {}", zip_member.name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!new_file->close()) {
|
if (!new_file->close()) {
|
||||||
warnln("Can't close file {}: {}", zip_member.name, new_file->error_string());
|
warnln("Can't close file {}: {}", zip_member.name, new_file->error_string());
|
||||||
return false;
|
return false;
|
||||||
|
@ -123,6 +141,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
TRY(Core::System::chdir(output_directory_path));
|
TRY(Core::System::chdir(output_directory_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<Archive::ZipMember> zip_directories;
|
||||||
|
|
||||||
auto success = TRY(zip_file->for_each_member([&](auto zip_member) {
|
auto success = TRY(zip_file->for_each_member([&](auto zip_member) {
|
||||||
bool keep_file = false;
|
bool keep_file = false;
|
||||||
|
|
||||||
|
@ -142,10 +162,23 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
if (keep_file) {
|
if (keep_file) {
|
||||||
if (!unpack_zip_member(zip_member, quiet))
|
if (!unpack_zip_member(zip_member, quiet))
|
||||||
return IterationDecision::Break;
|
return IterationDecision::Break;
|
||||||
|
if (zip_member.is_directory)
|
||||||
|
zip_directories.append(zip_member);
|
||||||
}
|
}
|
||||||
|
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& directory : zip_directories) {
|
||||||
|
if (adjust_modification_time(directory).is_error()) {
|
||||||
|
warnln("Failed setting modification time for directory {}", directory.name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return success ? 0 : 1;
|
return success ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/DOSPackedTime.h>
|
||||||
#include <AK/LexicalPath.h>
|
#include <AK/LexicalPath.h>
|
||||||
#include <LibArchive/Zip.h>
|
#include <LibArchive/Zip.h>
|
||||||
#include <LibCompress/Deflate.h>
|
#include <LibCompress/Deflate.h>
|
||||||
#include <LibCore/ArgsParser.h>
|
#include <LibCore/ArgsParser.h>
|
||||||
|
#include <LibCore/DateTime.h>
|
||||||
#include <LibCore/DirIterator.h>
|
#include <LibCore/DirIterator.h>
|
||||||
#include <LibCore/File.h>
|
#include <LibCore/File.h>
|
||||||
#include <LibCore/Stream.h>
|
#include <LibCore/Stream.h>
|
||||||
|
@ -58,6 +60,11 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
Archive::ZipMember member {};
|
Archive::ZipMember member {};
|
||||||
member.name = TRY(String::from_deprecated_string(canonicalized_path));
|
member.name = TRY(String::from_deprecated_string(canonicalized_path));
|
||||||
|
|
||||||
|
auto stat = TRY(Core::System::fstat(file->fd()));
|
||||||
|
auto date = Core::DateTime::from_timestamp(stat.st_mtim.tv_sec);
|
||||||
|
member.modification_date = to_packed_dos_date(date.year(), date.month(), date.day());
|
||||||
|
member.modification_time = to_packed_dos_time(date.hour(), date.minute(), date.second());
|
||||||
|
|
||||||
auto deflate_buffer = Compress::DeflateCompressor::compress_all(file_buffer);
|
auto deflate_buffer = Compress::DeflateCompressor::compress_all(file_buffer);
|
||||||
if (!deflate_buffer.is_error() && deflate_buffer.value().size() < file_buffer.size()) {
|
if (!deflate_buffer.is_error() && deflate_buffer.value().size() < file_buffer.size()) {
|
||||||
member.compressed_data = deflate_buffer.value().bytes();
|
member.compressed_data = deflate_buffer.value().bytes();
|
||||||
|
@ -85,6 +92,12 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
member.uncompressed_size = 0;
|
member.uncompressed_size = 0;
|
||||||
member.crc32 = 0;
|
member.crc32 = 0;
|
||||||
member.is_directory = true;
|
member.is_directory = true;
|
||||||
|
|
||||||
|
auto stat = TRY(Core::System::stat(canonicalized_path));
|
||||||
|
auto date = Core::DateTime::from_timestamp(stat.st_mtim.tv_sec);
|
||||||
|
member.modification_date = to_packed_dos_date(date.year(), date.month(), date.day());
|
||||||
|
member.modification_time = to_packed_dos_time(date.hour(), date.minute(), date.second());
|
||||||
|
|
||||||
TRY(zip_stream.add_member(member));
|
TRY(zip_stream.add_member(member));
|
||||||
outln(" adding: {} (stored 0%)", canonicalized_path);
|
outln(" adding: {} (stored 0%)", canonicalized_path);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue