git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 3/5] archive-zip: write ZIP dir entry directly to strbuf

From
René Scharfe <l.s.r@web.de>
Date
Apr 24, 2017, 17:31 UTC
Message-ID
<dda8fd49-87af-057d-d929-3240f8fb3d37@web.de>
In-Reply-To
<85f2b6d1-107b-0624-af82-92446f28269e@web.de>

Write all fields of the ZIP directory record for an archive entry in the right order directly into the strbuf instead of taking a detour through a struct. Do that at end, when we have all necessary data like checksum and compressed size. The fields are documented just as well, the code becomes shorter and we save an extra copy.

Signed-off-by: Rene Scharfe <l.s.r@web.de>
---
 archive-zip.c | 81 ++++++++++++++++++++---------------------------------------
 1 file changed, 27 insertions(+), 54 deletions(-)
diff --git a/archive-zip.c b/archive-zip.c
index a6fac59602..2d52bb3ade 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -45,27 +45,6 @@ struct zip_data_desc {
 	unsigned char _end[1];
 };
 
-struct zip_dir_header {
-	unsigned char magic[4];
-	unsigned char creator_version[2];
-	unsigned char version[2];
-	unsigned char flags[2];
-	unsigned char compression_method[2];
-	unsigned char mtime[2];
-	unsigned char mdate[2];
-	unsigned char crc32[4];
-	unsigned char compressed_size[4];
-	unsigned char size[4];
-	unsigned char filename_length[2];
-	unsigned char extra_length[2];
-	unsigned char comment_length[2];
-	unsigned char disk[2];
-	unsigned char attr1[2];
-	unsigned char attr2[4];
-	unsigned char offset[4];
-	unsigned char _end[1];
-};
-
 struct zip_dir_trailer {
 	unsigned char magic[4];
 	unsigned char disk[2];
@@ -166,6 +145,15 @@ static void copy_le16_clamp(unsigned char *dest, uint64_t n, int *clamped)
 	copy_le16(dest, clamp_max(n, 0xffff, clamped));
 }
 
+static int strbuf_add_le(struct strbuf *sb, size_t size, uintmax_t n)
+{
+	while (size-- > 0) {
+		strbuf_addch(sb, n & 0xff);
+		n >>= 8;
+	}
+	return -!!n;
+}
+
 static void *zlib_deflate_raw(void *data, unsigned long size,
 			      int compression_level,
 			      unsigned long *compressed_size)
@@ -212,16 +200,6 @@ static void write_zip_data_desc(unsigned long size,
 	write_or_die(1, &trailer, ZIP_DATA_DESC_SIZE);
 }
 
-static void set_zip_dir_data_desc(struct zip_dir_header *header,
-				  unsigned long size,
-				  unsigned long compressed_size,
-				  unsigned long crc)
-{
-	copy_le32(header->crc32, crc);
-	copy_le32(header->compressed_size, compressed_size);
-	copy_le32(header->size, size);
-}
-
 static void set_zip_header_data_desc(struct zip_local_header *header,
 				     unsigned long size,
 				     unsigned long compressed_size,
@@ -261,7 +239,7 @@ static int write_zip_entry(struct archiver_args *args,
 			   unsigned int mode)
 {
 	struct zip_local_header header;
-	struct zip_dir_header dirent;
+	uintmax_t offset = zip_offset;
 	struct zip_extra_mtime extra;
 	unsigned long attr2;
 	unsigned long compressed_size;
@@ -353,21 +331,6 @@ static int write_zip_entry(struct archiver_args *args,
 	extra.flags[0] = 1;	/* just mtime */
 	copy_le32(extra.mtime, args->time);
 
-	copy_le32(dirent.magic, 0x02014b50);
-	copy_le16(dirent.creator_version, creator_version);
-	copy_le16(dirent.version, 10);
-	copy_le16(dirent.flags, flags);
-	copy_le16(dirent.compression_method, method);
-	copy_le16(dirent.mtime, zip_time);
-	copy_le16(dirent.mdate, zip_date);
-	set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
-	copy_le16(dirent.filename_length, pathlen);
-	copy_le16(dirent.extra_length, ZIP_EXTRA_MTIME_SIZE);
-	copy_le16(dirent.comment_length, 0);
-	copy_le16(dirent.disk, 0);
-	copy_le32(dirent.attr2, attr2);
-	copy_le32(dirent.offset, zip_offset);
-
 	copy_le32(header.magic, 0x04034b50);
 	copy_le16(header.version, 10);
 	copy_le16(header.flags, flags);
@@ -406,8 +369,6 @@ static int write_zip_entry(struct archiver_args *args,
 
 		write_zip_data_desc(size, compressed_size, crc);
 		zip_offset += ZIP_DATA_DESC_SIZE;
-
-		set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
 	} else if (stream && method == 8) {
 		unsigned char buf[STREAM_BUFFER_SIZE];
 		ssize_t readlen;
@@ -464,8 +425,6 @@ static int write_zip_entry(struct archiver_args *args,
 
 		write_zip_data_desc(size, compressed_size, crc);
 		zip_offset += ZIP_DATA_DESC_SIZE;
-
-		set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
 	} else if (compressed_size > 0) {
 		write_or_die(1, out, compressed_size);
 		zip_offset += compressed_size;
@@ -474,9 +433,23 @@ static int write_zip_entry(struct archiver_args *args,
 	free(deflated);
 	free(buffer);
 
-	copy_le16(dirent.attr1, !is_binary);
-
-	strbuf_add(&zip_dir, &dirent, ZIP_DIR_HEADER_SIZE);
+	strbuf_add_le(&zip_dir, 4, 0x02014b50);	/* magic */
+	strbuf_add_le(&zip_dir, 2, creator_version);
+	strbuf_add_le(&zip_dir, 2, 10);		/* version */
+	strbuf_add_le(&zip_dir, 2, flags);
+	strbuf_add_le(&zip_dir, 2, method);
+	strbuf_add_le(&zip_dir, 2, zip_time);
+	strbuf_add_le(&zip_dir, 2, zip_date);
+	strbuf_add_le(&zip_dir, 4, crc);
+	strbuf_add_le(&zip_dir, 4, compressed_size);
+	strbuf_add_le(&zip_dir, 4, size);
+	strbuf_add_le(&zip_dir, 2, pathlen);
+	strbuf_add_le(&zip_dir, 2, ZIP_EXTRA_MTIME_SIZE);
+	strbuf_add_le(&zip_dir, 2, 0);		/* comment length */
+	strbuf_add_le(&zip_dir, 2, 0);		/* disk */
+	strbuf_add_le(&zip_dir, 2, !is_binary);
+	strbuf_add_le(&zip_dir, 4, attr2);
+	strbuf_add_le(&zip_dir, 4, offset);
 	strbuf_add(&zip_dir, path, pathlen);
 	strbuf_add(&zip_dir, &extra, ZIP_EXTRA_MTIME_SIZE);
 	zip_dir_entries++;
-- 
2.12.2
Previous: René ScharfeNext: René Scharfe
Message 15 of 44 in “Git archive doesn't fully support zip64”
  1. Keith GoldfarbApr 21, 2017
  2. archive-zip: Add zip64 headers when file size is too large for 32 bitsPeter Krefting, Apr 22, 2017
  3. Johannes SixtApr 22, 2017
  4. archive-zip: Add zip64 headers when file size is too large for 32 bitsPeter Krefting, Apr 22, 2017
  5. Johannes SixtApr 23, 2017
  6. Peter KreftingApr 23, 2017
  7. Johannes SixtApr 23, 2017
  8. Peter KreftingApr 24, 2017
  9. René ScharfeApr 24, 2017
  10. 0/5 archive-zip: support files and archives bigger than 4GBRené Scharfe, Apr 24, 2017
  11. 1/5 archive-zip: add tests for big ZIP archivesRené Scharfe, Apr 24, 2017
  12. 2/5 archive-zip: use strbuf for ZIP directoryRené Scharfe, Apr 24, 2017
  13. Junio C HamanoApr 25, 2017
  14. René ScharfeApr 25, 2017
  15. 3/5 archive-zip: write ZIP dir entry directly to strbufRené Scharfe, Apr 24, 2017
  16. 4/5 archive-zip: support archives bigger than 4GBRené Scharfe, Apr 24, 2017
  17. Peter KreftingApr 24, 2017
  18. René ScharfeApr 24, 2017
  19. René ScharfeApr 24, 2017
  20. Johannes SixtApr 24, 2017
  21. René ScharfeApr 24, 2017
  22. Peter KreftingApr 25, 2017
  23. René ScharfeApr 25, 2017
  24. Peter KreftingApr 26, 2017
  25. René ScharfeApr 26, 2017
  26. Peter KreftingApr 27, 2017
  27. René ScharfeApr 27, 2017
  28. Peter KreftingApr 28, 2017
  29. 5/5 archive-zip: support files bigger than 4GBRené Scharfe, Apr 24, 2017
  30. Keith GoldfarbApr 24, 2017
  31. Junio C HamanoApr 25, 2017
  32. René ScharfeApr 25, 2017
  33. Torsten BögershausenApr 29, 2017
  34. René ScharfeApr 29, 2017
  35. Torsten BögershausenApr 30, 2017
  36. René ScharfeApr 30, 2017
  37. Torsten BögershausenApr 30, 2017
  38. Johannes SixtApr 30, 2017
  39. René ScharfeApr 30, 2017
  40. Junio C HamanoApr 30, 2017
  41. René ScharfeMay 1, 2017
  42. René ScharfeApr 23, 2017
  43. Peter KreftingApr 23, 2017
  44. Johannes SixtApr 23, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.