diff options
author | Junio C Hamano <gitster@pobox.com> | 2012-05-22 15:34:46 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2012-05-22 15:34:46 -0700 |
commit | 423b5a104422d56645baf8229bfb496fa49c2a56 (patch) | |
tree | a7e020cab3c1a4d7c5b4eb04da55788e25bd6b81 | |
parent | tests: add tests for the bash prompt functions in the completion script (diff) | |
parent | completion: add new __git_complete helper (diff) | |
download | tgif-423b5a104422d56645baf8229bfb496fa49c2a56.tar.xz |
Merge branch 'fc/git-complete-helper' into fc/git-prompt-script
By Michael Haggerty (17) and others
via Junio C Hamano (36) and Jeff King (1)
* fc/git-complete-helper: (54 commits)
completion: add new __git_complete helper
Update draft release notes to 1.7.11 (11th batch)
Git 1.7.10.2
document submdule.$name.update=none option for gitmodules
The tenth batch of topics
Update draft release notes to 1.7.10.2
checkout: do not corrupt HEAD on empty repo
apply: remove lego in i18n string in gitdiff_verify_name
dir: convert to strbuf
status: refactor colopts handling
status: respect "-b" for porcelain format
status: fix null termination with "-b"
status: refactor null_termination option
commit: refactor option parsing
Documentation/git-config: describe and clarify "--local <file>" option
reflog-walk: tell explicit --date=default from not having --date at all
clone: fix progress-regression
grep.c: remove redundant line of code
checkout (detached): truncate list of orphaned commits at the new HEAD
t2020-checkout-detach: check for the number of orphaned commits
...
39 files changed, 1084 insertions, 527 deletions
diff --git a/Documentation/RelNotes/1.7.10.2.txt b/Documentation/RelNotes/1.7.10.2.txt index 04fe29404c..7a7e9d6fd1 100644 --- a/Documentation/RelNotes/1.7.10.2.txt +++ b/Documentation/RelNotes/1.7.10.2.txt @@ -14,6 +14,9 @@ Fixes since v1.7.10.1 * HTTP transport that requires authentication did not work correctly when multiple connections are used simultaneously. + * Minor memory leak during unpack_trees (hence "merge" and "checkout" + to check out another branch) has been plugged. + * In the older days, the header "Conflicts:" in "cherry-pick" and "merge" was separated by a blank line from the list of paths that follow for readability, but when "merge" was rewritten in C, we lost it by @@ -24,6 +27,9 @@ Fixes since v1.7.10.1 be both revision name and a pathname, even though $name can never be a path in the context of the command. + * The "include.path" facility in the configuration mechanism added in + 1.7.10 forgot to interpret "~/path" and "~user/path" as it should. + * "git config --rename-section" to rename an existing section into a bogus one did not check the new name. @@ -33,11 +39,44 @@ Fixes since v1.7.10.1 * The report from "git fetch" said "new branch" even for a non branch ref. + * The http-backend (the server side of the smart http transfer) used + to overwrite GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL with the + value obtained from REMOTE_USER unconditionally, making it + impossible for the server side site-specific customization to use + different identity sources to affect the names logged. It now uses + REMOTE_USER only as a fallback value. + + * "log --graph" was not very friendly with "--stat" option and its + output had line breaks at wrong places. + * Octopus merge strategy did not reduce heads that are recorded in the final commit correctly. + * "git push" over smart-http lost progress output a few releases ago; + this release resurrects it. + + * The error and advice messages given by "git push" when it fails due + to non-ff were not very helpful to new users; it has been broken + into three cases, and each is given a separate advice message. + + * The insn sheet given by "rebase -i" did not make it clear that the + insn lines can be re-ordered to affect the order of the commits in + the resulting history. + + * "git repack" used to write out unreachable objects as loose objects + when repacking, even if such loose objects will immediately pruned + due to its age. + + * A contrib script "rerere-train" did not work out of the box unless + user futzed with her $PATH. + + * "git rev-parse --show-prefix" used to emit nothing when run at the + top-level of the working tree, but now it gives a blank line. + * The i18n of error message "git stash save" was not properly done. + * "git submodule" used a sed script that some platforms mishandled. + * When using a Perl script on a system where "perl" found on user's $PATH could be ancient or otherwise broken, we allow builders to specify the path to a good copy of Perl with $PERL_PATH. The diff --git a/Documentation/RelNotes/1.7.11.txt b/Documentation/RelNotes/1.7.11.txt index 8dfeddcd68..9ef7e18ca5 100644 --- a/Documentation/RelNotes/1.7.11.txt +++ b/Documentation/RelNotes/1.7.11.txt @@ -25,13 +25,15 @@ UI, Workflows & Features tracking. Also "branch" learned the "-q"uiet option to squelch informational message. + * Your build platform may support hardlinks but you may prefer not to + use them, e.g. when installing to DESTDIR to make a tarball and + untarring on a filesystem that has poor support for hardlinks. + There is a Makefile option NO_INSTALL_HARDLINKS for you. + * The smart-http backend used to always override GIT_COMMITTER_* variables with REMOTE_USER and REMOTE_ADDR, but these variables are now preserved when set. - * "include.path" mechanism of the configuration files learned to - understand "~/path" and "~user/path". - * "git am" learned the "--include" option, which is an opposite of existing the "--exclude" option. @@ -51,9 +53,6 @@ UI, Workflows & Features * The "fmt-merge-msg" command learns to list the primary contributors involved in the side topic you are merging. - * The cases "git push" fails due to non-ff can be broken into three - categories; each case is given a separate advise message. - * "git rebase" learned to optionally keep commits that do not introduce any change in the original history. @@ -83,27 +82,20 @@ Performance and Internal Implementation (please report possible regressions) * An experimental "version 4" format of the index file has been introduced to reduce on-disk footprint and I/O overhead. + * "git archive" learned to produce its output without reading the + blob object it writes out in memory in its entirety. + * The code to compute hash values for lines used by the internal diff engine was optimized on little-endian machines, using the same trick the kernel folks came up with. * "git apply" had some memory leaks plugged. - * "git repack" used to write out unreachable objects as loose objects - when repacking, even if such loose objects will immediately pruned - due to its age. - * Setting up a revision traversal with many starting points was inefficient as these were placed in a date-order priority queue one-by-one. Now they are collected in the queue unordered first, and sorted immediately before getting used. - * "git rev-parse --show-prefix" used to emit nothing when run at the - top-level of the working tree, but now it gives a blank line. - - * Minor memory leak during unpack_trees (hence "merge" and "checkout" - to check out another branch) has been plugged. - * More lower-level commands learned to use the streaming API to read from the object store without keeping everything in core. @@ -124,6 +116,30 @@ Unless otherwise noted, all the fixes since v1.7.10 in the maintenance releases are contained in this release (see release notes to them for details). + * The DWIM behaviour for "log --pretty=format:%gd -g" was somewhat + broken and gave undue precedence to configured log.date, causing + "git stash list" to show "stash@{time stamp string}". + (merge 55ccf85 jk/maint-reflog-walk-count-vs-time later to maint). + + * Running "git checkout" on an unborn branch used to corrupt HEAD. + (merge 8338f77 ef/checkout-empty later to maint). + + * When checking out another commit from an already detached state, we + used to report all commits that are not reachable from any of the + refs as lossage, but some of them might be reachable from the new + HEAD, and there is no need to warn about them. + (merge 5d88639 js/checkout-detach-count later to maint). + + * Some time ago, "git clone" lost the progress output for its + "checkout" phase; when run without any "--quiet" option, it should + give progress to the lengthy operation. + (merge 8f63da1 ef/maint-clone-progress-fix later to maint). + + * "git status --porcelain" ignored "--branch" option by mistake. The + output for "git status --branch -z" was also incorrect and did not + terminate the record for the current branch name with NUL as asked. + (merge d4a6bf1 jk/maint-status-porcelain-z-b later to maint). + * "git diff --stat" used to fully count a binary file with modified execution bits whose contents is unmodified, which was not quite right. @@ -132,14 +148,3 @@ details). NUL. The fix is not entirely correct when the output also asks for --patch and/or --stat, though. (merge fafd382 jk/maint-tformat-with-z later to maint). - - * "git push" over smart-http lost progress output a few releases ago. - (merge e304aeb jk/maint-push-progress later to maint). - - * A contrib script "rerere-train" did not work out of the box unless - user futzed with her $PATH. - (merge 53876fc jc/rerere-train later to maint). - - * "log --graph" was not very friendly with "--stat" option and its - output had line breaks at wrong places. - (merge bafa16e lp/diffstat-with-graph later to maint). diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 81b03982e3..3f5d216a09 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -44,11 +44,15 @@ a "true" or "false" string for bool), or '--path', which does some path expansion (see '--path' below). If no type specifier is passed, no checks or transformations are performed on the value. -The file-option can be one of '--system', '--global' or '--file' -which specify where the values will be read from or written to. -The default is to assume the config file of the current repository, -.git/config unless defined otherwise with GIT_DIR and GIT_CONFIG -(see <<FILES>>). +When reading, the values are read from the system, global and +repository local configuration files by default, and options +'--system', '--global', '--local' and '--file <filename>' can be +used to tell the command to read from only that location (see <<FILES>>). + +When writing, the new value is written to the repository local +configuration file by default, and options '--system', '--global', +'--file <filename>' can be used to tell the command to write to +that location (you can say '--local' but that is the default). This command will fail (with exit code ret) if: diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index 2883a285ba..67e5f53a9e 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -184,7 +184,7 @@ order is reversed (e.g 'from \-> to' becomes 'to from'). Second, a NUL and the terminating newline (but a space still separates the status field from the first filename). Third, filenames containing special characters are not specially formatted; no quoting or -backslash-escaping is performed. Fourth, there is no branch line. +backslash-escaping is performed. CONFIGURATION ------------- diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index c243ee552b..c83a856574 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -140,7 +140,8 @@ update:: checkout the commit specified in the index of the containing repository. This will make the submodules HEAD be detached unless `--rebase` or `--merge` is specified or the key `submodule.$name.update` is set to - `rebase`, `merge` or `none`. + `rebase`, `merge` or `none`. `none` can be overriden by specifying + `--checkout`. + If the submodule is not yet initialized, and you just want to use the setting as stored in .gitmodules, you can automatically initialize the @@ -148,10 +149,6 @@ submodule with the `--init` option. + If `--recursive` is specified, this command will recurse into the registered submodules, and update any nested submodules within. -+ -If the configuration key `submodule.$name.update` is set to `none` the -submodule with name `$name` will not be updated by default. This can be -overriden by adding `--checkout` to the command. summary:: Show commit summary between the given commit (defaults to HEAD) and diff --git a/Documentation/git.txt b/Documentation/git.txt index 8527775988..c543213126 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -44,9 +44,10 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.7.10.1/git.html[documentation for release 1.7.10.1] +* link:v1.7.10.2/git.html[documentation for release 1.7.10.2] * release notes for + link:RelNotes/1.7.10.2.txt[1.7.10.2], link:RelNotes/1.7.10.1.txt[1.7.10.1], link:RelNotes/1.7.10.txt[1.7.10]. diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt index 4e1fd52e7d..4effd78902 100644 --- a/Documentation/gitmodules.txt +++ b/Documentation/gitmodules.txt @@ -41,8 +41,11 @@ submodule.<name>.update:: the commit specified in the superproject. If 'merge', the commit specified in the superproject will be merged into the current branch in the submodule. + If 'none', the submodule with name `$name` will not be updated + by default. + This config option is overridden if 'git submodule update' is given - the '--merge' or '--rebase' options. + the '--merge', '--rebase' or '--checkout' options. submodule.<name>.fetchRecurseSubmodules:: This option can be used to control recursive fetching of this @@ -247,6 +247,9 @@ all:: # Define NO_CROSS_DIRECTORY_HARDLINKS if you plan to distribute the installed # programs as a tar, where bin/ and libexec/ might be on different file systems. # +# Define NO_INSTALL_HARDLINKS if you prefer to use either symbolic links or +# copies to install built-in git commands e.g. git-cat-file. +# # Define USE_NED_ALLOCATOR if you want to replace the platforms default # memory allocators with the nedmalloc allocator written by Niall Douglas. # @@ -1835,6 +1838,10 @@ ifdef ASCIIDOC7 export ASCIIDOC7 endif +ifdef NO_INSTALL_HARDLINKS + export NO_INSTALL_HARDLINKS +endif + ### profile feedback build # @@ -2574,19 +2581,21 @@ endif { test "$$bindir/" = "$$execdir/" || \ for p in git$X $(filter $(install_bindir_programs),$(ALL_PROGRAMS)); do \ $(RM) "$$execdir/$$p" && \ - test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \ + test -z "$(NO_INSTALL_HARDLINKS)$(NO_CROSS_DIRECTORY_HARDLINKS)" && \ ln "$$bindir/$$p" "$$execdir/$$p" 2>/dev/null || \ cp "$$bindir/$$p" "$$execdir/$$p" || exit; \ done; \ } && \ for p in $(filter $(install_bindir_programs),$(BUILT_INS)); do \ $(RM) "$$bindir/$$p" && \ + test -z "$(NO_INSTALL_HARDLINKS)" && \ ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \ ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \ cp "$$bindir/git$X" "$$bindir/$$p" || exit; \ done && \ for p in $(BUILT_INS); do \ $(RM) "$$execdir/$$p" && \ + test -z "$(NO_INSTALL_HARDLINKS)" && \ ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \ ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \ cp "$$execdir/git$X" "$$execdir/$$p" || exit; \ @@ -2594,6 +2603,7 @@ endif remote_curl_aliases="$(REMOTE_CURL_ALIASES)" && \ for p in $$remote_curl_aliases; do \ $(RM) "$$execdir/$$p" && \ + test -z "$(NO_INSTALL_HARDLINKS)" && \ ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \ ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \ cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; \ diff --git a/archive-tar.c b/archive-tar.c index 20af0051a3..93387ea336 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -4,6 +4,7 @@ #include "cache.h" #include "tar.h" #include "archive.h" +#include "streaming.h" #include "run-command.h" #define RECORDSIZE (512) @@ -30,10 +31,9 @@ static void write_if_needed(void) * queues up writes, so that all our write(2) calls write exactly one * full block; pads writes to RECORDSIZE */ -static void write_blocked(const void *data, unsigned long size) +static void do_write_blocked(const void *data, unsigned long size) { const char *buf = data; - unsigned long tail; if (offset) { unsigned long chunk = BLOCKSIZE - offset; @@ -54,6 +54,11 @@ static void write_blocked(const void *data, unsigned long size) memcpy(block + offset, buf, size); offset += size; } +} + +static void finish_record(void) +{ + unsigned long tail; tail = offset % RECORDSIZE; if (tail) { memset(block + offset, 0, RECORDSIZE - tail); @@ -62,6 +67,12 @@ static void write_blocked(const void *data, unsigned long size) write_if_needed(); } +static void write_blocked(const void *data, unsigned long size) +{ + do_write_blocked(data, size); + finish_record(); +} + /* * The end of tar archives is marked by 2*512 nul bytes and after that * follows the rest of the block (if any). @@ -78,6 +89,33 @@ static void write_trailer(void) } /* + * queues up writes, so that all our write(2) calls write exactly one + * full block; pads writes to RECORDSIZE + */ +static int stream_blocked(const unsigned char *sha1) +{ + struct git_istream *st; + enum object_type type; + unsigned long sz; + char buf[BLOCKSIZE]; + ssize_t readlen; + + st = open_istream(sha1, &type, &sz, NULL); + if (!st) + return error("cannot stream blob %s", sha1_to_hex(sha1)); + for (;;) { + readlen = read_istream(st, buf, sizeof(buf)); + if (readlen <= 0) + break; + do_write_blocked(buf, readlen); + } + close_istream(st); + if (!readlen) + finish_record(); + return readlen; +} + +/* * pax extended header records have the format "%u %s=%s\n". %u contains * the size of the whole string (including the %u), the first %s is the * keyword, the second one is the value. This function constructs such a @@ -123,56 +161,101 @@ static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen) return i; } +static void prepare_header(struct archiver_args *args, + struct ustar_header *header, + unsigned int mode, unsigned long size) +{ + sprintf(header->mode, "%07o", mode & 07777); + sprintf(header->size, "%011lo", S_ISREG(mode) ? size : 0); + sprintf(header->mtime, "%011lo", (unsigned long) args->time); + + sprintf(header->uid, "%07o", 0); + sprintf(header->gid, "%07o", 0); + strlcpy(header->uname, "root", sizeof(header->uname)); + strlcpy(header->gname, "root", sizeof(header->gname)); + sprintf(header->devmajor, "%07o", 0); + sprintf(header->devminor, "%07o", 0); + + memcpy(header->magic, "ustar", 6); + memcpy(header->version, "00", 2); + + sprintf(header->chksum, "%07o", ustar_header_chksum(header)); +} + +static int write_extended_header(struct archiver_args *args, + const unsigned char *sha1, + const void *buffer, unsigned long size) +{ + struct ustar_header header; + unsigned int mode; + memset(&header, 0, sizeof(header)); + *header.typeflag = TYPEFLAG_EXT_HEADER; + mode = 0100666; + sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1)); + prepare_header(args, &header, mode, size); + write_blocked(&header, sizeof(header)); + write_blocked(buffer, size); + return 0; +} + static int write_tar_entry(struct archiver_args *args, - const unsigned char *sha1, const char *path, size_t pathlen, - unsigned int mode, void *buffer, unsigned long size) + const unsigned char *sha1, + const char *path, size_t pathlen, + unsigned int mode) { struct ustar_header header; struct strbuf ext_header = STRBUF_INIT; + unsigned int old_mode = mode; + unsigned long size; + void *buffer; int err = 0; memset(&header, 0, sizeof(header)); - if (!sha1) { - *header.typeflag = TYPEFLAG_GLOBAL_HEADER; - mode = 0100666; - strcpy(header.name, "pax_global_header"); - } else if (!path) { - *header.typeflag = TYPEFLAG_EXT_HEADER; - mode = 0100666; - sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1)); + if (S_ISDIR(mode) || S_ISGITLINK(mode)) { + *header.typeflag = TYPEFLAG_DIR; + mode = (mode | 0777) & ~tar_umask; + } else if (S_ISLNK(mode)) { + *header.typeflag = TYPEFLAG_LNK; + mode |= 0777; + } else if (S_ISREG(mode)) { + *header.typeflag = TYPEFLAG_REG; + mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask; } else { - if (S_ISDIR(mode) || S_ISGITLINK(mode)) { - *header.typeflag = TYPEFLAG_DIR; - mode = (mode | 0777) & ~tar_umask; - } else if (S_ISLNK(mode)) { - *header.typeflag = TYPEFLAG_LNK; - mode |= 0777; - } else if (S_ISREG(mode)) { - *header.typeflag = TYPEFLAG_REG; - mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask; + return error("unsupported file mode: 0%o (SHA1: %s)", + mode, sha1_to_hex(sha1)); + } + if (pathlen > sizeof(header.name)) { + size_t plen = get_path_prefix(path, pathlen, + sizeof(header.prefix)); + size_t rest = pathlen - plen - 1; + if (plen > 0 && rest <= sizeof(header.name)) { + memcpy(header.prefix, path, plen); + memcpy(header.name, path + plen + 1, rest); } else { - return error("unsupported file mode: 0%o (SHA1: %s)", - mode, sha1_to_hex(sha1)); + sprintf(header.name, "%s.data", + sha1_to_hex(sha1)); + strbuf_append_ext_header(&ext_header, "path", + path, pathlen); } - if (pathlen > sizeof(header.name)) { - size_t plen = get_path_prefix(path, pathlen, - sizeof(header.prefix)); - size_t rest = pathlen - plen - 1; - if (plen > 0 && rest <= sizeof(header.name)) { - memcpy(header.prefix, path, plen); - memcpy(header.name, path + plen + 1, rest); - } else { - sprintf(header.name, "%s.data", - sha1_to_hex(sha1)); - strbuf_append_ext_header(&ext_header, "path", - path, pathlen); - } - } else - memcpy(header.name, path, pathlen); + } else + memcpy(header.name, path, pathlen); + + if (S_ISREG(mode) && !args->convert && + sha1_object_info(sha1, &size) == OBJ_BLOB && + size > big_file_threshold) + buffer = NULL; + else if (S_ISLNK(mode) || S_ISREG(mode)) { + enum object_type type; + buffer = sha1_file_to_archive(args, path, sha1, old_mode, &type, &size); + if (!buffer) + return error("cannot read %s", sha1_to_hex(sha1)); + } else { + buffer = NULL; + size = 0; } - if (S_ISLNK(mode) && buffer) { + if (S_ISLNK(mode)) { if (size > sizeof(header.linkname)) { sprintf(header.linkname, "see %s.paxheader", sha1_to_hex(sha1)); @@ -182,32 +265,25 @@ static int write_tar_entry(struct archiver_args *args, memcpy(header.linkname, buffer, size); } - sprintf(header.mode, "%07o", mode & 07777); - sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0); - sprintf(header.mtime, "%011lo", (unsigned long) args->time); - - sprintf(header.uid, "%07o", 0); - sprintf(header.gid, "%07o", 0); - strlcpy(header.uname, "root", sizeof(header.uname)); - strlcpy(header.gname, "root", sizeof(header.gname)); - sprintf(header.devmajor, "%07o", 0); - sprintf(header.devminor, "%07o", 0); - - memcpy(header.magic, "ustar", 6); - memcpy(header.version, "00", 2); - - sprintf(header.chksum, "%07o", ustar_header_chksum(&header)); + prepare_header(args, &header, mode, size); if (ext_header.len > 0) { - err = write_tar_entry(args, sha1, NULL, 0, 0, ext_header.buf, - ext_header.len); - if (err) + err = write_extended_header(args, sha1, ext_header.buf, + ext_header.len); + if (err) { + free(buffer); return err; + } } strbuf_release(&ext_header); write_blocked(&header, sizeof(header)); - if (S_ISREG(mode) && buffer && size > 0) - write_blocked(buffer, size); + if (S_ISREG(mode) && size > 0) { + if (buffer) + write_blocked(buffer, size); + else + err = stream_blocked(sha1); + } + free(buffer); return err; } @@ -215,11 +291,18 @@ static int write_global_extended_header(struct archiver_args *args) { const unsigned char *sha1 = args->commit_sha1; struct strbuf ext_header = STRBUF_INIT; - int err; + struct ustar_header header; + unsigned int mode; + int err = 0; strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40); - err = write_tar_entry(args, NULL, NULL, 0, 0, ext_header.buf, - ext_header.len); + memset(&header, 0, sizeof(header)); + *header.typeflag = TYPEFLAG_GLOBAL_HEADER; + mode = 0100666; + strcpy(header.name, "pax_global_header"); + prepare_header(args, &header, mode, ext_header.len); + write_blocked(&header, sizeof(header)); + write_blocked(ext_header.buf, ext_header.len); strbuf_release(&ext_header); return err; } diff --git a/archive-zip.c b/archive-zip.c index 02d1f3787a..f5af81f904 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -3,6 +3,7 @@ */ #include "cache.h" #include "archive.h" +#include "streaming.h" static int zip_date; static int zip_time; @@ -15,6 +16,7 @@ static unsigned int zip_dir_offset; static unsigned int zip_dir_entries; #define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024) +#define ZIP_STREAM (8) struct zip_local_header { unsigned char magic[4]; @@ -31,6 +33,14 @@ struct zip_local_header { unsigned char _end[1]; }; +struct zip_data_desc { + unsigned char magic[4]; + unsigned char crc32[4]; + unsigned char compressed_size[4]; + unsigned char size[4]; + unsigned char _end[1]; +}; + struct zip_dir_header { unsigned char magic[4]; unsigned char creator_version[2]; @@ -70,6 +80,7 @@ struct zip_dir_trailer { * we're interested in. */ #define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end) +#define ZIP_DATA_DESC_SIZE offsetof(struct zip_data_desc, _end) #define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end) #define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end) @@ -120,20 +131,59 @@ static void *zlib_deflate(void *data, unsigned long size, return buffer; } +static void write_zip_data_desc(unsigned long size, + unsigned long compressed_size, + unsigned long crc) +{ + struct zip_data_desc trailer; + + copy_le32(trailer.magic, 0x08074b50); + copy_le32(trailer.crc32, crc); + copy_le32(trailer.compressed_size, compressed_size); + copy_le32(trailer.size, 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, |