mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-20 01:37:39 +03:00
LibArchive: Add support for modification time and date
This commit is contained in:
parent
361df6eff8
commit
0ce1c52577
Notes:
sideshowbarker
2024-07-17 10:05:47 +09:00
Author: https://github.com/Ollrogge Commit: https://github.com/SerenityOS/serenity/commit/0ce1c52577 Pull-request: https://github.com/SerenityOS/serenity/pull/17224 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/AtkinsSJ Reviewed-by: https://github.com/drunderscore Reviewed-by: https://github.com/timschumi
@ -90,6 +90,8 @@ ErrorOr<bool> Zip::for_each_member(Function<IterationDecision(ZipMember const&)>
|
||||
member.compression_method = central_directory_record.compression_method;
|
||||
member.uncompressed_size = central_directory_record.uncompressed_size;
|
||||
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
|
||||
|
||||
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),
|
||||
.general_purpose_flags = { .flags = 0 },
|
||||
.compression_method = static_cast<u16>(member.compression_method),
|
||||
.modification_time = 0, // TODO: support modification time
|
||||
.modification_date = 0,
|
||||
.modification_time = member.modification_time,
|
||||
.modification_date = member.modification_date,
|
||||
.crc32 = member.crc32,
|
||||
.compressed_size = static_cast<u32>(member.compressed_data.size()),
|
||||
.uncompressed_size = member.uncompressed_size,
|
||||
@ -150,8 +152,8 @@ ErrorOr<void> ZipOutputStream::finish()
|
||||
.minimum_version = zip_version,
|
||||
.general_purpose_flags = { .flags = 0 },
|
||||
.compression_method = member.compression_method,
|
||||
.modification_time = 0, // TODO: support modification time
|
||||
.modification_date = 0,
|
||||
.modification_time = member.modification_time,
|
||||
.modification_date = member.modification_date,
|
||||
.crc32 = member.crc32,
|
||||
.compressed_size = static_cast<u32>(member.compressed_data.size()),
|
||||
.uncompressed_size = member.uncompressed_size,
|
||||
|
@ -8,6 +8,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/DOSPackedTime.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/IterationDecision.h>
|
||||
#include <AK/String.h>
|
||||
@ -112,8 +113,8 @@ struct [[gnu::packed]] CentralDirectoryRecord {
|
||||
u16 minimum_version;
|
||||
ZipGeneralPurposeFlags general_purpose_flags;
|
||||
ZipCompressionMethod compression_method;
|
||||
u16 modification_time;
|
||||
u16 modification_date;
|
||||
DOSPackedTime modification_time;
|
||||
DOSPackedDate modification_date;
|
||||
u32 crc32;
|
||||
u32 compressed_size;
|
||||
u32 uncompressed_size;
|
||||
@ -186,8 +187,8 @@ struct [[gnu::packed]] LocalFileHeader {
|
||||
u16 minimum_version;
|
||||
ZipGeneralPurposeFlags general_purpose_flags;
|
||||
u16 compression_method;
|
||||
u16 modification_time;
|
||||
u16 modification_date;
|
||||
DOSPackedTime modification_time;
|
||||
DOSPackedDate modification_date;
|
||||
u32 crc32;
|
||||
u32 compressed_size;
|
||||
u32 uncompressed_size;
|
||||
@ -244,6 +245,8 @@ struct ZipMember {
|
||||
u32 uncompressed_size;
|
||||
u32 crc32;
|
||||
bool is_directory;
|
||||
DOSPackedTime modification_time;
|
||||
DOSPackedDate modification_date;
|
||||
};
|
||||
|
||||
class Zip {
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/DOSPackedTime.h>
|
||||
#include <AK/NumberFormat.h>
|
||||
#include <AK/StringUtils.h>
|
||||
#include <LibArchive/Zip.h>
|
||||
@ -17,6 +18,18 @@
|
||||
#include <LibCrypto/Checksum/CRC32.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)
|
||||
{
|
||||
if (zip_member.is_directory) {
|
||||
@ -69,6 +82,11 @@ static bool unpack_zip_member(Archive::ZipMember zip_member, bool quiet)
|
||||
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()) {
|
||||
warnln("Can't close file {}: {}", zip_member.name, new_file->error_string());
|
||||
return false;
|
||||
@ -123,6 +141,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
TRY(Core::System::chdir(output_directory_path));
|
||||
}
|
||||
|
||||
Vector<Archive::ZipMember> zip_directories;
|
||||
|
||||
auto success = TRY(zip_file->for_each_member([&](auto zip_member) {
|
||||
bool keep_file = false;
|
||||
|
||||
@ -142,10 +162,23 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
if (keep_file) {
|
||||
if (!unpack_zip_member(zip_member, quiet))
|
||||
return IterationDecision::Break;
|
||||
if (zip_member.is_directory)
|
||||
zip_directories.append(zip_member);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -4,10 +4,12 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/DOSPackedTime.h>
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <LibArchive/Zip.h>
|
||||
#include <LibCompress/Deflate.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibCore/DateTime.h>
|
||||
#include <LibCore/DirIterator.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibCore/Stream.h>
|
||||
@ -58,6 +60,11 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
Archive::ZipMember member {};
|
||||
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);
|
||||
if (!deflate_buffer.is_error() && deflate_buffer.value().size() < file_buffer.size()) {
|
||||
member.compressed_data = deflate_buffer.value().bytes();
|
||||
@ -85,6 +92,12 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
member.uncompressed_size = 0;
|
||||
member.crc32 = 0;
|
||||
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));
|
||||
outln(" adding: {} (stored 0%)", canonicalized_path);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user