Skip to content

Commit 38af842

Browse files
improve Unix/MS-DOS metadata support
1 parent 054cd74 commit 38af842

14 files changed

+982
-48
lines changed

index.d.ts

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -986,14 +986,78 @@ export interface EntryMetaData {
986986
* `true` if `internalFileAttributes` and `externalFileAttributes` are compatible with MS-DOS format.
987987
*/
988988
msDosCompatible: boolean;
989+
/**
990+
* Note (MS-DOS / Unix attributes):
991+
*
992+
* - The single source of truth for on-disk metadata is the 32-bit `externalFileAttributes` value stored in
993+
* the ZIP headers. The upper 16 bits are commonly used for Unix `st_mode` (type/permissions/special bits)
994+
* and the low 8 bits for MS-DOS attribute flags.
995+
*
996+
* - Writer vs Reader:
997+
* - The writer composes `externalFileAttributes` from the provided options (`externalFileAttributes`,
998+
* `unixMode`/special flags, `msdosAttributesRaw`/`msdosAttributes`).
999+
* - The reader decodes the stored `externalFileAttributes` and exposes convenience fields such as
1000+
* `msdosAttributesRaw`, `msdosAttributes`, `unixExternalUpper`, and `unixMode`.
1001+
*
1002+
* - Practical rule: treat `externalFileAttributes` as authoritative; other fields are conveniences derived
1003+
* from it. If you need a specific on-disk value, set `externalFileAttributes` explicitly.
1004+
*/
1005+
/**
1006+
* The MS-DOS attributes low byte (raw).
1007+
* This is the low 8 bits of {@link EntryMetaData#externalFileAttributes} when present.
1008+
*/
1009+
msdosAttributesRaw?: number;
1010+
/**
1011+
* The MS-DOS attribute flags exposed as booleans.
1012+
*/
1013+
msdosAttributes?: {
1014+
readOnly: boolean;
1015+
hidden: boolean;
1016+
system: boolean;
1017+
directory: boolean;
1018+
archive: boolean;
1019+
};
1020+
/**
1021+
* Unix owner id when available.
1022+
*/
1023+
uid?: number;
1024+
/**
1025+
* Unix group id when available.
1026+
*/
1027+
gid?: number;
1028+
/**
1029+
* Unix mode (st_mode) when available.
1030+
*/
1031+
unixMode?: number;
1032+
/**
1033+
* `true` if the setuid bit is set on the entry.
1034+
*/
1035+
setuid?: boolean;
1036+
/**
1037+
* `true` if the setgid bit is set on the entry.
1038+
*/
1039+
setgid?: boolean;
1040+
/**
1041+
* `true` if the sticky bit is set on the entry.
1042+
*/
1043+
sticky?: boolean;
9891044
/**
9901045
* The internal file attributes (raw).
9911046
*/
9921047
internalFileAttributes: number;
9931048
/**
994-
* The external file attributes (raw).
1049+
* The 32-bit `externalFileAttributes` field is the authoritative on-disk metadata for each entry.
1050+
* - Upper 16 bits: Unix mode/type (e.g., permissions, file type)
1051+
* - Low 8 bits: MS-DOS file attributes (e.g., directory, read-only)
1052+
*
1053+
* When writing, all provided options are merged into this field. When reading, convenience fields are decoded from it.
1054+
* For most use cases, prefer the high-level options and fields; only advanced users need to manipulate the raw value directly.
9951055
*/
9961056
externalFileAttributes: number;
1057+
/**
1058+
* The upper 16-bit portion of {@link EntryMetaData#externalFileAttributes} when it represents Unix mode bits.
1059+
*/
1060+
unixExternalUpper?: number;
9971061
/**
9981062
* The number of the disk where the entry data starts.
9991063
*/
@@ -1478,12 +1542,57 @@ export interface ZipWriterConstructorOptions {
14781542
* @defaultValue 0
14791543
*/
14801544
externalFileAttributes?: number;
1545+
/**
1546+
* The Unix owner id to write in the Unix extra field or as part of the external attributes.
1547+
*/
1548+
uid?: number;
1549+
/**
1550+
* The Unix group id to write in the Unix extra field or as part of the external attributes.
1551+
*/
1552+
gid?: number;
1553+
/**
1554+
* The Unix mode (st_mode bits) to use when writing external attributes.
1555+
*/
1556+
unixMode?: number;
1557+
/**
1558+
* `true` to set the setuid bit when writing the Unix mode.
1559+
*/
1560+
setuid?: boolean;
1561+
/**
1562+
* `true` to set the setgid bit when writing the Unix mode.
1563+
*/
1564+
setgid?: boolean;
1565+
/**
1566+
* `true` to set the sticky bit when writing the Unix mode.
1567+
*/
1568+
sticky?: boolean;
1569+
/**
1570+
* Which Unix extra field format to write when creating entries that include Unix metadata.
1571+
* - "infozip": use Info-ZIP New Unix extra field
1572+
* - "unix": use the traditional Unix extra field format
1573+
*/
1574+
unixExtraFieldType?: "infozip" | "unix";
14811575
/**
14821576
* The internal file attribute.
14831577
*
14841578
* @defaultValue 0
14851579
*/
14861580
internalFileAttributes?: number;
1581+
/**
1582+
* When provided, the low 8-bit MS-DOS attributes to write into external file attributes.
1583+
* Must be an integer between 0 and 255.
1584+
*/
1585+
msdosAttributesRaw?: number;
1586+
/**
1587+
* When provided, MS-DOS attribute flags (boolean object) to write into external file attributes low byte.
1588+
*/
1589+
msdosAttributes?: {
1590+
readOnly?: boolean;
1591+
hidden?: boolean;
1592+
system?: boolean;
1593+
directory?: boolean;
1594+
archive?: boolean;
1595+
};
14871596
/**
14881597
* `false` to never write disk numbers in zip64 data.
14891598
*

lib/core/constants.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ const EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP = 0x5455;
5858
const EXTRAFIELD_TYPE_UNICODE_PATH = 0x7075;
5959
const EXTRAFIELD_TYPE_UNICODE_COMMENT = 0x6375;
6060
const EXTRAFIELD_TYPE_USDZ = 0x1986;
61+
const EXTRAFIELD_TYPE_INFOZIP = 0x7875;
62+
const EXTRAFIELD_TYPE_UNIX = 0x7855;
6163

6264
const BITFLAG_ENCRYPTED = 0b1;
6365
const BITFLAG_LEVEL = 0b0110;
@@ -67,10 +69,17 @@ const BITFLAG_LEVEL_SUPER_FAST_MASK = 0b110;
6769
const BITFLAG_DATA_DESCRIPTOR = 0b1000;
6870
const BITFLAG_LANG_ENCODING_FLAG = 0b100000000000;
6971
const FILE_ATTR_MSDOS_DIR_MASK = 0b10000;
72+
const FILE_ATTR_MSDOS_READONLY_MASK = 0x01;
73+
const FILE_ATTR_MSDOS_HIDDEN_MASK = 0x02;
74+
const FILE_ATTR_MSDOS_SYSTEM_MASK = 0x04;
75+
const FILE_ATTR_MSDOS_ARCHIVE_MASK = 0x20;
7076
const FILE_ATTR_UNIX_TYPE_MASK = 0o170000;
7177
const FILE_ATTR_UNIX_TYPE_DIR = 0o040000;
7278
const FILE_ATTR_UNIX_EXECUTABLE_MASK = 0o111;
7379
const FILE_ATTR_UNIX_DEFAULT_MASK = 0o644;
80+
const FILE_ATTR_UNIX_SETUID_MASK = 0o4000;
81+
const FILE_ATTR_UNIX_SETGID_MASK = 0o2000;
82+
const FILE_ATTR_UNIX_STICKY_MASK = 0o1000;
7483

7584
const VERSION_DEFLATE = 0x14;
7685
const VERSION_ZIP64 = 0x2D;
@@ -117,6 +126,8 @@ export {
117126
EXTRAFIELD_TYPE_UNICODE_PATH,
118127
EXTRAFIELD_TYPE_UNICODE_COMMENT,
119128
EXTRAFIELD_TYPE_USDZ,
129+
EXTRAFIELD_TYPE_INFOZIP,
130+
EXTRAFIELD_TYPE_UNIX,
120131
END_OF_CENTRAL_DIR_LENGTH,
121132
ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH,
122133
ZIP64_END_OF_CENTRAL_DIR_LENGTH,
@@ -129,10 +140,17 @@ export {
129140
BITFLAG_DATA_DESCRIPTOR,
130141
BITFLAG_LANG_ENCODING_FLAG,
131142
FILE_ATTR_MSDOS_DIR_MASK,
143+
FILE_ATTR_MSDOS_READONLY_MASK,
144+
FILE_ATTR_MSDOS_HIDDEN_MASK,
145+
FILE_ATTR_MSDOS_SYSTEM_MASK,
146+
FILE_ATTR_MSDOS_ARCHIVE_MASK,
132147
FILE_ATTR_UNIX_TYPE_MASK,
133148
FILE_ATTR_UNIX_TYPE_DIR,
134149
FILE_ATTR_UNIX_EXECUTABLE_MASK,
135150
FILE_ATTR_UNIX_DEFAULT_MASK,
151+
FILE_ATTR_UNIX_SETUID_MASK,
152+
FILE_ATTR_UNIX_SETGID_MASK,
153+
FILE_ATTR_UNIX_STICKY_MASK,
136154
VERSION_DEFLATE,
137155
VERSION_ZIP64,
138156
VERSION_AES,

lib/core/options.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ const OPTION_SUPPORT_ZIP64_SPLIT_FILE = "supportZip64SplitFile";
5555
const OPTION_ENCODE_TEXT = "encodeText";
5656
const OPTION_OFFSET = "offset";
5757
const OPTION_USDZ = "usdz";
58+
const OPTION_UNIX_EXTRA_FIELD_TYPE = "unixExtraFieldType";
5859

5960
export {
6061
OPTION_FILENAME_ENCODING,
@@ -85,5 +86,6 @@ export {
8586
OPTION_SUPPORT_ZIP64_SPLIT_FILE,
8687
OPTION_ENCODE_TEXT,
8788
OPTION_OFFSET,
88-
OPTION_USDZ
89+
OPTION_USDZ,
90+
OPTION_UNIX_EXTRA_FIELD_TYPE
8991
};

lib/core/zip-entry.js

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ const PROPERTY_NAME_CREATION_DATE = "creationDate";
4242
const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
4343
const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
4444
const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
45+
const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
46+
const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
4547
const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
4648
const PROPERTY_NAME_ZIP64 = "zip64";
4749
const PROPERTY_NAME_ENCRYPTED = "encrypted";
@@ -53,17 +55,73 @@ const PROPERTY_NAME_EXECUTABLE = "executable";
5355
const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
5456
const PROPERTY_NAME_SIGNATURE = "signature";
5557
const PROPERTY_NAME_EXTRA_FIELD = "extraField";
58+
const PROPERTY_NAME_EXTRA_FIELD_INFOZIP = "extraFieldInfoZip";
59+
const PROPERTY_NAME_EXTRA_FIELD_UNIX = "extraFieldUnix";
60+
const PROPERTY_NAME_UID = "uid";
61+
const PROPERTY_NAME_GID = "gid";
62+
const PROPERTY_NAME_UNIX_MODE = "unixMode";
63+
const PROPERTY_NAME_SETUID = "setuid";
64+
const PROPERTY_NAME_SETGID = "setgid";
65+
const PROPERTY_NAME_STICKY = "sticky";
66+
const PROPERTY_NAME_BITFLAG = "bitFlag";
67+
const PROPERTY_NAME_FILENAME_UTF8 = "filenameUTF8";
68+
const PROPERTY_NAME_COMMENT_UTF8 = "commentUTF8";
69+
const PROPERTY_NAME_RAW_EXTRA_FIELD = "rawExtraField";
70+
const PROPERTY_NAME_EXTRA_FIELD_ZIP64 = "extraFieldZip64";
71+
const PROPERTY_NAME_EXTRA_FIELD_UNICODE_PATH = "extraFieldUnicodePath";
72+
const PROPERTY_NAME_EXTRA_FIELD_UNICODE_COMMENT = "extraFieldUnicodeComment";
73+
const PROPERTY_NAME_EXTRA_FIELD_AES = "extraFieldAES";
74+
const PROPERTY_NAME_EXTRA_FIELD_NTFS = "extraFieldNTFS";
75+
const PROPERTY_NAME_EXTRA_FIELD_EXTENDED_TIMESTAMP = "extraFieldExtendedTimestamp";
5676

5777
const PROPERTY_NAMES = [
58-
PROPERTY_NAME_FILENAME, PROPERTY_NAME_RAW_FILENAME, PROPERTY_NAME_COMPRESSED_SIZE, PROPERTY_NAME_UNCOMPRESSED_SIZE,
59-
PROPERTY_NAME_LAST_MODIFICATION_DATE, PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE, PROPERTY_NAME_COMMENT, PROPERTY_NAME_RAW_COMMENT,
60-
PROPERTY_NAME_LAST_ACCESS_DATE, PROPERTY_NAME_CREATION_DATE, PROPERTY_NAME_OFFSET, PROPERTY_NAME_DISK_NUMBER_START,
61-
PROPERTY_NAME_DISK_NUMBER_START, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
62-
PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_MS_DOS_COMPATIBLE, PROPERTY_NAME_ZIP64,
63-
PROPERTY_NAME_ENCRYPTED, PROPERTY_NAME_VERSION, PROPERTY_NAME_VERSION_MADE_BY, PROPERTY_NAME_ZIPCRYPTO, PROPERTY_NAME_DIRECTORY,
64-
PROPERTY_NAME_EXECUTABLE, PROPERTY_NAME_COMPRESSION_METHOD, PROPERTY_NAME_SIGNATURE, PROPERTY_NAME_EXTRA_FIELD,
65-
"bitFlag", "filenameUTF8", "commentUTF8", "rawExtraField", "extraFieldZip64", "extraFieldUnicodePath", "extraFieldUnicodeComment",
66-
"extraFieldAES", "extraFieldNTFS", "extraFieldExtendedTimestamp"];
78+
PROPERTY_NAME_FILENAME,
79+
PROPERTY_NAME_RAW_FILENAME,
80+
PROPERTY_NAME_UNCOMPRESSED_SIZE,
81+
PROPERTY_NAME_COMPRESSED_SIZE,
82+
PROPERTY_NAME_LAST_MODIFICATION_DATE,
83+
PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE,
84+
PROPERTY_NAME_COMMENT,
85+
PROPERTY_NAME_RAW_COMMENT,
86+
PROPERTY_NAME_LAST_ACCESS_DATE,
87+
PROPERTY_NAME_CREATION_DATE,
88+
PROPERTY_NAME_RAW_CREATION_DATE,
89+
PROPERTY_NAME_OFFSET,
90+
PROPERTY_NAME_DISK_NUMBER_START,
91+
PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
92+
PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
93+
PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
94+
PROPERTY_NAME_MSDOS_ATTRIBUTES,
95+
PROPERTY_NAME_MS_DOS_COMPATIBLE,
96+
PROPERTY_NAME_ZIP64,
97+
PROPERTY_NAME_ENCRYPTED,
98+
PROPERTY_NAME_VERSION,
99+
PROPERTY_NAME_VERSION_MADE_BY,
100+
PROPERTY_NAME_ZIPCRYPTO,
101+
PROPERTY_NAME_DIRECTORY,
102+
PROPERTY_NAME_EXECUTABLE,
103+
PROPERTY_NAME_COMPRESSION_METHOD,
104+
PROPERTY_NAME_SIGNATURE,
105+
PROPERTY_NAME_EXTRA_FIELD,
106+
PROPERTY_NAME_EXTRA_FIELD_UNIX,
107+
PROPERTY_NAME_EXTRA_FIELD_INFOZIP,
108+
PROPERTY_NAME_UID,
109+
PROPERTY_NAME_GID,
110+
PROPERTY_NAME_UNIX_MODE,
111+
PROPERTY_NAME_SETUID,
112+
PROPERTY_NAME_SETGID,
113+
PROPERTY_NAME_STICKY,
114+
PROPERTY_NAME_BITFLAG,
115+
PROPERTY_NAME_FILENAME_UTF8,
116+
PROPERTY_NAME_COMMENT_UTF8,
117+
PROPERTY_NAME_RAW_EXTRA_FIELD,
118+
PROPERTY_NAME_EXTRA_FIELD_ZIP64,
119+
PROPERTY_NAME_EXTRA_FIELD_UNICODE_PATH,
120+
PROPERTY_NAME_EXTRA_FIELD_UNICODE_COMMENT,
121+
PROPERTY_NAME_EXTRA_FIELD_AES,
122+
PROPERTY_NAME_EXTRA_FIELD_NTFS,
123+
PROPERTY_NAME_EXTRA_FIELD_EXTENDED_TIMESTAMP
124+
];
67125

68126
class Entry {
69127

@@ -90,6 +148,8 @@ export {
90148
PROPERTY_NAME_RAW_CREATION_DATE,
91149
PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
92150
PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
151+
PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
152+
PROPERTY_NAME_MSDOS_ATTRIBUTES,
93153
PROPERTY_NAME_MS_DOS_COMPATIBLE,
94154
PROPERTY_NAME_ZIP64,
95155
PROPERTY_NAME_ENCRYPTED,
@@ -101,5 +161,11 @@ export {
101161
PROPERTY_NAME_COMPRESSION_METHOD,
102162
PROPERTY_NAME_SIGNATURE,
103163
PROPERTY_NAME_EXTRA_FIELD,
164+
PROPERTY_NAME_GID,
165+
PROPERTY_NAME_UID,
166+
PROPERTY_NAME_UNIX_MODE,
167+
PROPERTY_NAME_SETUID,
168+
PROPERTY_NAME_SETGID,
169+
PROPERTY_NAME_STICKY,
104170
Entry
105171
};

0 commit comments

Comments
 (0)