patterns/zip: Added parsing of extra field (#182)

* zip pattern: Improved fallback method for finding eocd. Added test data to cover this edge case

* zip pattern: added parsing of extra field
This commit is contained in:
Hugo
2023-10-29 19:47:11 +01:00
committed by GitHub
parent e0a602c10a
commit 27e55d2e6d
3 changed files with 95 additions and 2 deletions

View File

@@ -155,6 +155,15 @@ namespace std::time {
return converter.time;
};
/**
Converts a FILETIME to unix time.
@param value The value to convert.
@return Timestamp formatted as unix time.
*/
fn filetime_to_unix(u64 value) {
return value / 10000000 - 11644473600;
};
/**
Formats a time according to the specified format string.
@param time The time to format.

View File

@@ -34,6 +34,11 @@ namespace type {
*/
using DOSTime = u16 [[format("type::impl::format_dostime")]];
/**
A 64bit FILETIME value
*/
using FILETIME = u64 [[format("type::impl::format_filetime_as_unix")]];
namespace impl {
fn format_time_t(u128 value) {
@@ -48,6 +53,10 @@ namespace type {
return std::time::format_dos_time(std::time::to_dos_time(value));
};
fn format_filetime_as_unix(u64 value) {
return std::time::filetime_to_unix(value);
};
}
}

View File

@@ -4,6 +4,7 @@
#include <std/mem.pat>
#include <std/math.pat>
#include <type/time.pat>
struct EndOfCentralDirectory {
u32 headerSignature [[comment("EoCD magic"), name("EoCD PK\\5\\6")]];
@@ -17,6 +18,78 @@ struct EndOfCentralDirectory {
char coment[commentLength] [[name("Comment")]];
};
namespace extra {
bitfield Flags {
bool modification_time_set : 1;
bool access_time_set : 1;
bool creation_time_set : 1;
reserved: 5; //reserved for additional timestamps; not set
};
struct X5455_ExtendedTimestamp {
Flags Flags;
if (Flags.modification_time_set){
u32 ModTime;
}
if (Flags.access_time_set){
u32 AcTime;
}
if (Flags.creation_time_set){
u32 CrTime;
}
};
struct X000A_NTFS {
u32 reserved;
u16 tag;
u16 TSize;
//Timestamps are in FILETIME format. Converted to Unix for easier handling.
type::FILETIME ModTime;
type::FILETIME AcTime;
type::FILETIME CrTime;
};
struct X7875_NewUnix {
u16 tag;
u16 TSize;
u8 version;
u8 UIDSize;
u8 UID[UIDSize];
u8 GIDSize;
u8 GID[GIDSize];
};
struct X5855_InfoZipUnix {
u32 AcTime;
u32 ModTime;
if (parent.TSize > 8){
u16 UID;
}
if (parent.TSize > 10){
u16 GID;
}
};
struct ExtraField {
u16 tag;
u16 TSize;
if (tag == 0x5455){
extra::X5455_ExtendedTimestamp x5455_ExtendedTimestamp;
}else if (tag == 0x000a){
extra::X000A_NTFS x000A_NTFS;
}else if (tag == 0x7875){
extra::X7875_NewUnix x7875_NewUnix;
}else if (tag == 0x5855){
extra::X5855_InfoZipUnix x5855_InfoZipUnix;
}else{
std::print("Unsupported tag 0x{:02X}", tag);
padding[TSize];
}
};
}
fn find_eocd() {
// If there is no zip comment, which is the common case,
// the end-of-central-directory record will be 22 bytes long
@@ -96,7 +169,8 @@ struct LocalFileHeader {
u16 fileNameLength [[ comment("File name length (n)") ]];
u16 extraFieldLength [[ comment("Extra field length (m)") ]];
char fileName[fileNameLength] [[ comment("File Name") ]];
char extraField[extraFieldLength] [[ comment("Extra Field") ]];
u64 extraEnd = $ + extraFieldLength;
extra::ExtraField extraFields[while ($ < extraEnd)] [[comment("Extra Fields")]];
u8 data[compressedSize] [[name("File Data")]];
};
@@ -124,7 +198,8 @@ struct CentralDirectoryFileHeader {
u32 externalFileAttributes;
File file;
char fileName[fileNameLength];
u8 extraField[extraFieldLength];
u64 extraEnd = $ + extraFieldLength;
extra::ExtraField extraFields[while ($ < extraEnd)] [[comment("Extra Fields")]];
char comment[fileCommentLength];
};