libarchive/test/test_read_format_7zip_ppmd.7z.uu \
libarchive/test/test_read_format_7zip_solid_zstd.7z.uu \
libarchive/test/test_read_format_7zip_symbolic_name.7z.uu \
+ libarchive/test/test_read_format_7zip_win_attrib.7z.uu \
libarchive/test/test_read_format_7zip_zstd_arm.7z.uu \
libarchive/test/test_read_format_7zip_zstd_bcj.7z.uu \
libarchive/test/test_read_format_7zip_zstd_nobcj.7z.uu \
#define kEncodedHeader 0x17
#define kDummy 0x19
+// Check that some windows file attribute constants are defined.
+// Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
+#ifndef FILE_ATTRIBUTE_READONLY
+#define FILE_ATTRIBUTE_READONLY 0x00000001
+#endif
+
+#ifndef FILE_ATTRIBUTE_HIDDEN
+#define FILE_ATTRIBUTE_HIDDEN 0x00000002
+#endif
+
+#ifndef FILE_ATTRIBUTE_SYSTEM
+#define FILE_ATTRIBUTE_SYSTEM 0x00000004
+#endif
+
+#ifndef FILE_ATTRIBUTE_DIRECTORY
+#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
+#endif
+
+// This value is defined in 7zip with the comment "trick for Unix".
+//
+// 7z archives created on unix have this bit set in the high 16 bits of
+// the attr field along with the unix permissions.
+#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000
+
struct _7z_digests {
unsigned char *defineds;
uint32_t *digests;
archive_entry_set_size(entry, 0);
}
+ // These attributes are supported by the windows implementation of archive_write_disk.
+ const int supported_attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
+
+ if (zip_entry->attr & supported_attrs) {
+ char *fflags_text, *ptr;
+ /* allocate for "rdonly,hidden,system," */
+ fflags_text = malloc(22 * sizeof(char));
+ if (fflags_text != NULL) {
+ ptr = fflags_text;
+ if (zip_entry->attr & FILE_ATTRIBUTE_READONLY) {
+ strcpy(ptr, "rdonly,");
+ ptr = ptr + 7;
+ }
+ if (zip_entry->attr & FILE_ATTRIBUTE_HIDDEN) {
+ strcpy(ptr, "hidden,");
+ ptr = ptr + 7;
+ }
+ if (zip_entry->attr & FILE_ATTRIBUTE_SYSTEM) {
+ strcpy(ptr, "system,");
+ ptr = ptr + 7;
+ }
+ if (ptr > fflags_text) {
+ /* Delete trailing comma */
+ *(ptr - 1) = '\0';
+ archive_entry_copy_fflags_text(entry,
+ fflags_text);
+ }
+ free(fflags_text);
+ }
+ }
+
/* If there's no body, force read_data() to return EOF immediately. */
if (zip->entry_bytes_remaining < 1)
zip->end_of_entry = 1;
entries[i].flg |= HAS_STREAM;
/* The high 16 bits of attributes is a posix file mode. */
entries[i].mode = entries[i].attr >> 16;
+
+ if (!(entries[i].attr & FILE_ATTRIBUTE_UNIX_EXTENSION)) {
+ // Only windows permissions specified for this entry. Translate to
+ // reasonable corresponding unix permissions.
+
+ if (entries[i].attr & FILE_ATTRIBUTE_DIRECTORY) {
+ if (entries[i].attr & FILE_ATTRIBUTE_READONLY) {
+ // Read-only directory.
+ entries[i].mode = AE_IFDIR | 0555;
+ } else {
+ // Read-write directory.
+ entries[i].mode = AE_IFDIR | 0755;
+ }
+ } else if (entries[i].attr & FILE_ATTRIBUTE_READONLY) {
+ // Readonly file.
+ entries[i].mode = AE_IFREG | 0444;
+ } else {
+ // Assume read-write file.
+ entries[i].mode = AE_IFREG | 0644;
+ }
+ }
+
if (entries[i].flg & HAS_STREAM) {
if ((size_t)sindex >= si->ss.unpack_streams)
return (-1);
}
entries[i].ssIndex = -1;
}
- if (entries[i].attr & 0x01)
+ if (entries[i].attr & FILE_ATTRIBUTE_READONLY)
entries[i].mode &= ~0222;/* Read only. */
if ((entries[i].flg & HAS_STREAM) == 0 && indexInFolder == 0) {
#define kAttributes 0x15
#define kEncodedHeader 0x17
+// Check that some windows file attribute constants are defined.
+// Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
+#ifndef FILE_ATTRIBUTE_READONLY
+#define FILE_ATTRIBUTE_READONLY 0x00000001
+#endif
+
+#ifndef FILE_ATTRIBUTE_DIRECTORY
+#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
+#endif
+
+#ifndef FILE_ATTRIBUTE_ARCHIVE
+#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
+#endif
+
+// This value is defined in 7zip with the comment "trick for Unix".
+//
+// 7z archives created on unix have this bit set in the high 16 bits of
+// the attr field along with the unix permissions.
+#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000
+
enum la_zaction {
ARCHIVE_Z_FINISH,
ARCHIVE_Z_RUN
* High 16bits is unix mode.
* Low 16bits is Windows attributes.
*/
- uint32_t encattr, attr;
+ uint32_t encattr, attr = 0;
+
if (file->dir)
- attr = 0x8010;
+ attr |= FILE_ATTRIBUTE_DIRECTORY;
else
- attr = 0x8020;
+ attr |= FILE_ATTRIBUTE_ARCHIVE;
+
if ((file->mode & 0222) == 0)
- attr |= 1;/* Read Only. */
+ attr |= FILE_ATTRIBUTE_READONLY;
+
+ attr |= FILE_ATTRIBUTE_UNIX_EXTENSION;
attr |= ((uint32_t)file->mode) << 16;
+
archive_le32enc(&encattr, attr);
r = (int)compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);
if (r < 0)
/* Verify regular file1. */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
- assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae));
+ assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
assertEqualString("file1", archive_entry_pathname(ae));
assertEqualInt(86401, archive_entry_mtime(ae));
assertEqualInt(60, archive_entry_size(ae));
/* Verify regular file1. */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
- assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae));
+ assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
assertEqualString("ppmd_test.txt", archive_entry_pathname(ae));
assertEqualInt(1322464589, archive_entry_mtime(ae));
assertEqualInt(102400, archive_entry_size(ae));
test_arm64_filter("test_read_format_7zip_deflate_arm64.7z");
}
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_read_format_7zip_win_attrib)
+{
+ struct archive *a;
+
+ assert((a = archive_read_new()) != NULL);
+
+ if (ARCHIVE_OK != archive_read_support_filter_lzma(a)) {
+ skipping(
+ "7zip:lzma decoding is not supported on this platform");
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+ return;
+ }
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+
+ // This archive has four files and four directories:
+ // * hidden directory
+ // * readonly directory
+ // * regular directory
+ // * system directory
+ // * regular "archive" file
+ // * hidden file
+ // * readonly file
+ // * system file
+ const char *refname = "test_read_format_7zip_win_attrib.7z";
+ extract_reference_file(refname);
+
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, 10240));
+
+ struct archive_entry *ae;
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("hidden_dir/", archive_entry_pathname(ae));
+ assertEqualInt((AE_IFDIR | 0755), archive_entry_mode(ae));
+ assertEqualString("hidden", archive_entry_fflags_text(ae));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("readonly_dir/", archive_entry_pathname(ae));
+ assertEqualInt((AE_IFDIR | 0555), archive_entry_mode(ae));
+ assertEqualString("rdonly", archive_entry_fflags_text(ae));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("regular_dir/", archive_entry_pathname(ae));
+ assertEqualInt((AE_IFDIR | 0755), archive_entry_mode(ae));
+ assertEqualString(NULL, archive_entry_fflags_text(ae));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("system_dir/", archive_entry_pathname(ae));
+ assertEqualInt((AE_IFDIR | 0755), archive_entry_mode(ae));
+ assertEqualString("system", archive_entry_fflags_text(ae));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("archive_file.txt", archive_entry_pathname(ae));
+ assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
+ assertEqualString(NULL, archive_entry_fflags_text(ae));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("hidden_file.txt", archive_entry_pathname(ae));
+ assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
+ assertEqualString("hidden", archive_entry_fflags_text(ae));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("readonly_file.txt", archive_entry_pathname(ae));
+ assertEqualInt((AE_IFREG | 0444), archive_entry_mode(ae));
+ assertEqualString("rdonly", archive_entry_fflags_text(ae));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("system_file.txt", archive_entry_pathname(ae));
+ assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
+ assertEqualString("system", archive_entry_fflags_text(ae));
+
+
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
/* Verify regular file1. */
assertEqualIntA(a, ARCHIVE_OK,
archive_read_next_header(a, &ae));
- assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae));
+ assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
assertEqualString("a.txt", archive_entry_pathname(ae));
assertEqualInt(1576808819, archive_entry_mtime(ae));
assertEqualInt(4, archive_entry_size(ae));
/* Verify regular file2. */
assertEqualIntA(a, ARCHIVE_OK,
archive_read_next_header(a, &ae));
- assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae));
+ assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
assertEqualString("b.txt", archive_entry_pathname(ae));
assertEqualInt(1576808819, archive_entry_mtime(ae));
assertEqualInt(4, archive_entry_size(ae));
--- /dev/null
+begin 644 test_read_format_7zip_win_attrib.7z
+M-WJ\KR<<``0:MZ25^0`````````B`````````,/QN>$!`!IA<F-H:79E:&ED
+M9&5N<F5A9&]N;'ES>7-T96T```"!,P>N#\_\\&P/Z^J<OS8]_GH-_C9=&O:;
+MN?AF5PM%@/8R"MH"PK!D-+92R@HB57B\_G7B9D`HLH<G4Z@!).&WAAA(R4U?
+M%0%=EB_VM=2[WZJHK$/PHCG(E(Y#O[W'JQD2%>%U\S6&7C"[<$<2GL2\B,**
+MW`0[F2;R)EO2:N)4RB6G.3+R6%97BQ]K"X),-'`E&./R#`2A\R&D1#U8FUC&
+MANR65$7S:?$CR7DS8<)L'MR%.5Y)T-;62DU\S8W?$4=U2972R-0]5J81R3E/
+M\K&`%O\H:/`E4``7!A\!"8#:``<+`0`!(P,!`05=`!````R!C@H!`M-R5@``
+`
+end