diff options
58 files changed, 1310 insertions, 790 deletions
diff --git a/Documentation/RelNotes-1.6.0.1.txt b/Documentation/RelNotes-1.6.0.1.txt new file mode 100644 index 0000000000..bac117e89d --- /dev/null +++ b/Documentation/RelNotes-1.6.0.1.txt @@ -0,0 +1,31 @@ +GIT v1.6.0.1 Release Notes +========================== + +Fixes since v1.6.0 +------------------ + +* "git diff --check" incorrectly detected new trailing blank lines when + whitespace check was in effect. + +* "git for-each-ref" tried to dereference NULL when asked for '%(body)" on + a tag with a single incomplete line as its payload. + +* "git format-patch" peeked before the beginning of a string when + "format.headers" variable is empty (a misconfiguration). + +* "git mailinfo" (hence "git am") was unhappy when MIME multipart message + contained garbage after the finishing boundary. + +* "git mailinfo" also was unhappy when the "From: " line only had a bare + e-mail address. + +* "git merge" did not refresh the index correctly when a merge resulted in + a fast-forward. + +Contains other various documentation fixes. + +-- +exec >/var/tmp/1 +O=v1.6.0-14-g3a634dc +echo O=$(git describe maint) +git shortlog --no-merges $O..maint diff --git a/Documentation/RelNotes-1.6.0.txt b/Documentation/RelNotes-1.6.0.txt index 9e2e417ef7..de7ef166b6 100644 --- a/Documentation/RelNotes-1.6.0.txt +++ b/Documentation/RelNotes-1.6.0.txt @@ -245,15 +245,14 @@ Fixes since v1.5.6 All of the fixes in v1.5.6 maintenance series are included in this release, unless otherwise noted. -* git-clone ignored its -u option; the fix needs to be backported to - 'maint'; - -* git-mv used to lose the distinction between changes that are staged - and that are only in the working tree, by staging both in the index - after moving such a path. - ---- -exec >/var/tmp/1 -O=v1.6.0-rc3 -echo O=$(git describe refs/heads/master) -git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint + * git-clone ignored its -u option; the fix needs to be backported to + 'maint'; + + * git-mv used to lose the distinction between changes that are staged + and that are only in the working tree, by staging both in the index + after moving such a path. + + * "git-rebase -i -p" rewrote the parents to wrong ones when amending + (either edit or squash) was involved, and did not work correctly + when fast forwarding. + diff --git a/Documentation/RelNotes-1.6.1.txt b/Documentation/RelNotes-1.6.1.txt new file mode 100644 index 0000000000..d37da039f6 --- /dev/null +++ b/Documentation/RelNotes-1.6.1.txt @@ -0,0 +1,58 @@ +GIT v1.6.1 Release Notes +======================== + +Updates since v1.6.0 +-------------------- + +When some commands (e.g. "git log", "git diff") spawn pager internally, we +used to make the pager the parent process of the git command that produces +output. This meant that the exit status of the whole thing comes from the +pager, not the underlying git command. We swapped the order of the +processes around and you will see the exit code from the command from now +on. + +(subsystems) + +* ... + +(portability) + +* ... + +(documentation) + +* ... + +(performance) + +* The underlying diff machinery to produce textual output has been + optimized, which would result in faster "git blame" processing. + +(usability, bells and whistles) + +* "git checkout --track origin/hack" used to be a syntax error. It now + DWIMs to create a corresponding local branch "hack", i.e. acts as if you + said "git checkout --track -b hack origin/hack". + +* "git diff" learned to mimick --suppress-blank-empty from GNU diff via a + configuration option. + +* "git imap-send" can optionally talk SSL. + +(internal) + +* "git hash-object" learned to lie about the path being hashed, so that + correct gitattributes processing can be done while hashing contents + stored in a temporary file. + +Fixes since v1.6.0 +------------------ + +All of the fixes in v1.6.0.X maintenance series are included in this +release, unless otherwise noted. + +-- +exec >/var/tmp/1 +O=v1.6.0-48-ge28a867 +echo O=$(git describe master) +git shortlog --no-merges $O..master ^maint diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 841bead9db..a1e9100f9e 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -71,7 +71,7 @@ run git diff --check on your changes before you commit. (1a) Try to be nice to older C compilers -We try to support wide range of C compilers to compile +We try to support a wide range of C compilers to compile git with. That means that you should not use C99 initializers, even if a lot of compilers grok it. diff --git a/Documentation/config.txt b/Documentation/config.txt index 676c39bb84..9020675866 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -567,6 +567,10 @@ diff.autorefreshindex:: affects only 'git-diff' Porcelain, and not lower level 'diff' commands, such as 'git-diff-files'. +diff.suppress-blank-empty:: + A boolean to inhibit the standard behavior of printing a space + before each empty output line. Defaults to false. + diff.external:: If this config variable is set, diff generation is not performed using the internal diff machinery, but using the diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index cba90fd27c..1759386404 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -107,9 +107,9 @@ endif::git-format-patch[] --exit-code. --full-index:: - Instead of the first handful characters, show full - object name of pre- and post-image blob on the "index" - line when generating a patch format output. + Instead of the first handful of characters, show the full + pre- and post-image blob object names on the "index" + line when generating patch format output. --binary:: In addition to --full-index, output "binary diff" that diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 5aa69c0e12..43d4502547 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -8,7 +8,7 @@ git-checkout - Checkout a branch or paths to the working tree SYNOPSIS -------- [verse] -'git checkout' [-q] [-f] [[--track | --no-track] -b <new_branch> [-l]] [-m] [<branch>] +'git checkout' [-q] [-f] [--track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>] 'git checkout' [<tree-ish>] [--] <paths>... DESCRIPTION @@ -21,6 +21,10 @@ specified, <new_branch>. Using -b will cause <new_branch> to be created; in this case you can use the --track or --no-track options, which will be passed to `git branch`. +As a convenience, --track will default to create a branch whose +name is constructed from the specified branch name by stripping +the first namespace level. + When <paths> are given, this command does *not* switch branches. It updates the named paths in the working tree from the index file (i.e. it runs `git checkout-index -f -u`), or @@ -59,6 +63,10 @@ OPTIONS 'git-checkout' and 'git-branch' to always behave as if '--no-track' were given. Set it to `always` if you want this behavior when the start-point is either a local or remote branch. ++ +If no '-b' option was given, a name will be made up for you, by stripping +the part up to the first slash of the tracked branch. For example, if you +called 'git checkout --track origin/next', the branch name will be 'next'. --no-track:: Ignore the branch.autosetupmerge configuration variable. diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt index c2d3c90d27..785779e221 100644 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@ -11,7 +11,7 @@ SYNOPSIS SSH: [verse] -export CVS_SERVER=git-cvsserver +export CVS_SERVER="git cvsserver" 'cvs' -d :ext:user@server/path/repo.git co <HEAD_name> pserver (/etc/inetd.conf): @@ -109,7 +109,7 @@ Note: Newer CVS versions (>= 1.12.11) also support specifying CVS_SERVER directly in CVSROOT like ------ -cvs -d ":ext;CVS_SERVER=git-cvsserver:user@server/path/repo.git" co <HEAD_name> +cvs -d ":ext;CVS_SERVER=git cvsserver:user@server/path/repo.git" co <HEAD_name> ------ This has the advantage that it will be saved in your 'CVS/Root' files and you don't need to worry about always setting the correct environment @@ -158,7 +158,7 @@ allowing access over SSH. -- ------ export CVSROOT=:ext:user@server:/var/git/project.git - export CVS_SERVER=git-cvsserver + export CVS_SERVER="git cvsserver" ------ -- 4. For SSH clients that will make commits, make sure their server-side @@ -283,7 +283,7 @@ To get a checkout with the Eclipse CVS client: Protocol notes: If you are using anonymous access via pserver, just select that. Those using SSH access should choose the 'ext' protocol, and configure 'ext' access on the Preferences->Team->CVS->ExtConnection pane. Set CVS_SERVER to -'git-cvsserver'. Note that password support is not good when using 'ext', +"'git cvsserver'". Note that password support is not good when using 'ext', you will definitely want to have SSH keys setup. Alternatively, you can just use the non-standard extssh protocol that Eclipse diff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.txt index ac928e198e..0af40cfb85 100644 --- a/Documentation/git-hash-object.txt +++ b/Documentation/git-hash-object.txt @@ -8,7 +8,9 @@ git-hash-object - Compute object ID and optionally creates a blob from a file SYNOPSIS -------- -'git hash-object' [-t <type>] [-w] [--stdin | --stdin-paths] [--] <file>... +[verse] +'git hash-object' [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>... +'git hash-object' [-t <type>] [-w] --stdin-paths < <list-of-paths> DESCRIPTION ----------- @@ -35,6 +37,22 @@ OPTIONS --stdin-paths:: Read file names from stdin instead of from the command-line. +--path:: + Hash object as it were located at the given path. The location of + file does not directly influence on the hash value, but path is + used to determine what git filters should be applied to the object + before it can be placed to the object database, and, as result of + applying filters, the actual blob put into the object database may + differ from the given file. This option is mainly useful for hashing + temporary files located outside of the working directory or files + read from stdin. + +--no-filters:: + Hash the contents as is, ignoring any input filter that would + have been chosen by the attributes mechanism, including crlf + conversion. If the file is read from standard input then this + is always implied, unless the --path option is given. + Author ------ Written by Junio C Hamano <gitster@pobox.com> diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt index b3d8da33ee..bd49a0aee8 100644 --- a/Documentation/git-imap-send.txt +++ b/Documentation/git-imap-send.txt @@ -3,7 +3,7 @@ git-imap-send(1) NAME ---- -git-imap-send - Dump a mailbox from stdin into an imap folder +git-imap-send - Send a collection of patches from stdin to an IMAP folder SYNOPSIS @@ -13,9 +13,9 @@ SYNOPSIS DESCRIPTION ----------- -This command uploads a mailbox generated with git-format-patch -into an imap drafts folder. This allows patches to be sent as -other email is sent with mail clients that cannot read mailbox +This command uploads a mailbox generated with 'git-format-patch' +into an IMAP drafts folder. This allows patches to be sent as +other email is when using mail clients that cannot read mailbox files directly. Typical usage is something like: @@ -26,21 +26,75 @@ git format-patch --signoff --stdout --attach origin | git imap-send CONFIGURATION ------------- -'git-imap-send' requires the following values in the repository -configuration file (shown with examples): +To use the tool, imap.folder and either imap.tunnel or imap.host must be set +to appropriate values. + +Variables +~~~~~~~~~ + +imap.folder:: + The folder to drop the mails into, which is typically the Drafts + folder. For example: "INBOX.Drafts", "INBOX/Drafts" or + "[Gmail]/Drafts". Required to use imap-send. + +imap.tunnel:: + Command used to setup a tunnel to the IMAP server through which + commands will be piped instead of using a direct network connection + to the server. Required when imap.host is not set to use imap-send. + +imap.host:: + A URL identifying the server. Use a `imap://` prefix for non-secure + connections and a `imaps://` prefix for secure connections. + Ignored when imap.tunnel is set, but required to use imap-send + otherwise. + +imap.user:: + The username to use when logging in to the server. + +imap.password:: + The password to use when logging in to the server. + +imap.port:: + An integer port number to connect to on the server. + Defaults to 143 for imap:// hosts and 993 for imaps:// hosts. + Ignored when imap.tunnel is set. + +imap.sslverify:: + A boolean to enable/disable verification of the server certificate + used by the SSL/TLS connection. Default is `true`. Ignored when + imap.tunnel is set. + +Examples +~~~~~~~~ + +Using tunnel mode: .......................... [imap] - Folder = "INBOX.Drafts" + folder = "INBOX.Drafts" + tunnel = "ssh -q -C user@example.com /usr/bin/imapd ./Maildir 2> /dev/null" +.......................... +Using direct mode: + +......................... [imap] - Tunnel = "ssh -q user@server.com /usr/bin/imapd ./Maildir 2> /dev/null" + folder = "INBOX.Drafts" + host = imap://imap.example.com + user = bob + pass = p4ssw0rd +.......................... + +Using direct mode with SSL: +......................... [imap] - Host = imap.server.com - User = bob - Pass = pwd - Port = 143 + folder = "INBOX.Drafts" + host = imaps://imap.example.com + user = bob + pass = p4ssw0rd + port = 123 + sslverify = false .......................... diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt index 98cfa3c0d0..caa07298a6 100644 --- a/Documentation/git-revert.txt +++ b/Documentation/git-revert.txt @@ -15,6 +15,15 @@ Given one existing commit, revert the change the patch introduces, and record a new commit that records it. This requires your working tree to be clean (no modifications from the HEAD commit). +Note: 'git revert' is used to record a new commit to reverse the +effect of an earlier commit (often a faulty one). If you want to +throw away all uncommitted changes in your working directory, you +should see linkgit:git-reset[1], particularly the '--hard' option. If +you want to extract specific files as they were in another commit, you +should see linkgit:git-checkout[1], specifically the 'git checkout +<commit> -- <filename>' syntax. Take care with these alternatives as +both will discard uncommitted changes in your working directory. + OPTIONS ------- <commit>:: diff --git a/Documentation/git.txt b/Documentation/git.txt index b1cb972369..1bc295dd54 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,6 +43,11 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: +* link:v1.6.0/git.html[documentation for release 1.6.0] + +* release notes for + link:RelNotes-1.6.0.txt[1.6.0]. + * link:v1.5.6.5/git.html[documentation for release 1.5.6.5] * release notes for diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index e1290d8901..156dc13733 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.5.6.GIT +DEF_VER=v1.6.0.GIT LF=' ' @@ -124,6 +124,9 @@ all:: # Define USE_STDEV below if you want git to care about the underlying device # change being considered an inode change from the update-index perspective. # +# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks +# field that counts the on-disk footprint in 512-byte blocks. +# # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 # # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. @@ -575,9 +578,11 @@ EXTLIBS = ifeq ($(uname_S),Linux) NO_STRLCPY = YesPlease + THREADED_DELTA_SEARCH = YesPlease endif ifeq ($(uname_S),GNU/kFreeBSD) NO_STRLCPY = YesPlease + THREADED_DELTA_SEARCH = YesPlease endif ifeq ($(uname_S),UnixWare) CC = cc @@ -675,6 +680,7 @@ ifeq ($(uname_S),FreeBSD) BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease + THREADED_DELTA_SEARCH = YesPlease endif ifeq ($(uname_S),OpenBSD) NO_STRCASESTR = YesPlease @@ -682,6 +688,7 @@ ifeq ($(uname_S),OpenBSD) NEEDS_LIBICONV = YesPlease BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib + THREADED_DELTA_SEARCH = YesPlease endif ifeq ($(uname_S),NetBSD) ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2) @@ -690,6 +697,7 @@ ifeq ($(uname_S),NetBSD) BASIC_CFLAGS += -I/usr/pkg/include BASIC_LDFLAGS += -L/usr/pkg/lib ALL_LDFLAGS += -Wl,-rpath,/usr/pkg/lib + THREADED_DELTA_SEARCH = YesPlease endif ifeq ($(uname_S),AIX) NO_STRCASESTR=YesPlease @@ -749,6 +757,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease + NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -863,6 +872,9 @@ endif ifdef NO_D_INO_IN_DIRENT BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT endif +ifdef NO_ST_BLOCKS_IN_STRUCT_STAT + BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT +endif ifdef NO_C99_FORMAT BASIC_CFLAGS += -DNO_C99_FORMAT endif @@ -1215,7 +1227,9 @@ endif git-%$X: %.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) -git-imap-send$X: imap-send.o $(LIB_FILE) +git-imap-send$X: imap-send.o $(GITLIBS) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ + $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) http.o http-walker.o http-push.o transport.o: http.h @@ -1 +1 @@ -Documentation/RelNotes-1.6.0.txt
\ No newline at end of file +Documentation/RelNotes-1.6.1.txt
\ No newline at end of file diff --git a/builtin-blame.c b/builtin-blame.c index 4ea343189f..e4d12de8a9 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -465,7 +465,6 @@ struct patch { }; struct blame_diff_state { - struct xdiff_emit_state xm; struct patch *ret; unsigned hunk_post_context; unsigned hunk_in_pre_context : 1; @@ -528,15 +527,12 @@ static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o, xpp.flags = xdl_opts; memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = context; - ecb.outf = xdiff_outf; - ecb.priv = &state; memset(&state, 0, sizeof(state)); - state.xm.consume = process_u_diff; state.ret = xmalloc(sizeof(struct patch)); state.ret->chunks = NULL; state.ret->num = 0; - xdi_diff(file_p, file_o, &xpp, &xecfg, &ecb); + xdi_diff_outf(file_p, file_o, process_u_diff, &state, &xpp, &xecfg, &ecb); if (state.ret->num) { struct chunk *chunk; diff --git a/builtin-checkout.c b/builtin-checkout.c index 411cc513c6..e95eab9b1b 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -437,13 +437,28 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); - opts.track = git_branch_track; + opts.track = -1; argc = parse_options(argc, argv, options, checkout_usage, PARSE_OPT_KEEP_DASHDASH); - if (!opts.new_branch && (opts.track != git_branch_track)) - die("git checkout: --track and --no-track require -b"); + /* --track without -b should DWIM */ + if (opts.track && opts.track != -1 && !opts.new_branch) { + char *slash; + if (!argc || !strcmp(argv[0], "--")) + die ("--track needs a branch name"); + slash = strchr(argv[0], '/'); + if (slash && !prefixcmp(argv[0], "refs/")) + slash = strchr(slash + 1, '/'); + if (slash && !prefixcmp(argv[0], "remotes/")) + slash = strchr(slash + 1, '/'); + if (!slash || !slash[1]) + die ("Missing branch name; try -b"); + opts.new_branch = slash + 1; + } + + if (opts.track == -1) + opts.track = git_branch_track; if (opts.force && opts.merge) die("git checkout: -f and -m are incompatible"); diff --git a/builtin-count-objects.c b/builtin-count-objects.c index 91b5487478..a1c9eb41cb 100644 --- a/builtin-count-objects.c +++ b/builtin-count-objects.c @@ -43,7 +43,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose, if (lstat(path, &st) || !S_ISREG(st.st_mode)) bad = 1; else - (*loose_size) += xsize_t(st.st_blocks); + (*loose_size) += xsize_t(on_disk_bytes(st)); } if (bad) { if (verbose) { @@ -115,7 +115,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix) num_pack++; } printf("count: %lu\n", loose); - printf("size: %lu\n", loose_size / 2); + printf("size: %lu\n", loose_size / 1024); printf("in-pack: %lu\n", packed); printf("packs: %lu\n", num_pack); printf("prune-packable: %lu\n", packed_loose); diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 445039e19c..4d25ec51d0 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -459,8 +459,10 @@ static void find_subpos(const char *buf, unsigned long sz, const char **sub, con return; *sub = buf; /* first non-empty line */ buf = strchr(buf, '\n'); - if (!buf) + if (!buf) { + *body = ""; return; /* no body */ + } while (*buf == '\n') buf++; /* skip blank between subject and body */ *body = buf; diff --git a/builtin-log.c b/builtin-log.c index f4975cf35f..911fd65990 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -461,7 +461,7 @@ static int extra_cc_alloc; static void add_header(const char *value) { int len = strlen(value); - while (value[len - 1] == '\n') + while (len && value[len - 1] == '\n') len--; if (!strncasecmp(value, "to: ", 4)) { ALLOC_GROW(extra_to, extra_to_nr + 1, extra_to_alloc); diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c index 3577382d70..e890f7a6d1 100644 --- a/builtin-mailinfo.c +++ b/builtin-mailinfo.c @@ -107,7 +107,7 @@ static void handle_from(const struct strbuf *from) el = strcspn(at, " \n\t\r\v\f>"); strbuf_reset(&email); strbuf_add(&email, at, el); - strbuf_remove(&f, at - f.buf, el + 1); + strbuf_remove(&f, at - f.buf, el + (at[el] ? 1 : 0)); /* The remainder is name. It could be "John Doe <john.doe@xz>" * or "john.doe@xz (John Doe)", but we have removed the @@ -175,7 +175,7 @@ static void handle_content_type(struct strbuf *line) message_type = TYPE_OTHER; if (slurp_attr(line->buf, "boundary=", boundary)) { strbuf_insert(boundary, 0, "--", 2); - if (content_top++ >= &content[MAX_BOUNDARIES]) { + if (++content_top > &content[MAX_BOUNDARIES]) { fprintf(stderr, "Too many boundaries to handle\n"); exit(1); } @@ -603,7 +603,7 @@ static void handle_filter(struct strbuf *line); static int find_boundary(void) { while (!strbuf_getline(&line, fin, '\n')) { - if (is_multipart_boundary(&line)) + if (*content_top && is_multipart_boundary(&line)) return 1; } return 0; @@ -626,7 +626,7 @@ again: /* technically won't happen as is_multipart_boundary() will fail first. But just in case.. */ - if (content_top-- < content) { + if (--content_top < content) { fprintf(stderr, "Detected mismatched boundaries, " "can't recover\n"); exit(1); diff --git a/builtin-merge.c b/builtin-merge.c index dde0c7ed33..a201c6628d 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -566,6 +566,7 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote) if (read_cache_unmerged()) die("you need to resolve your current index first"); + refresh_cache(REFRESH_QUIET); fd = hold_locked_index(lock_file, 1); @@ -936,7 +937,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix) hex, find_unique_abbrev(remoteheads->item->object.sha1, DEFAULT_ABBREV)); - refresh_cache(REFRESH_QUIET); strbuf_init(&msg, 0); strbuf_addstr(&msg, "Fast forward"); if (have_message) @@ -391,7 +391,6 @@ extern int ie_modified(const struct index_state *, struct cache_entry *, struct extern int ce_path_match(const struct cache_entry *ce, const char **pathspec); extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path); -extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object); extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object); extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); diff --git a/combine-diff.c b/combine-diff.c index 9f80a1c5e3..31ec0c5165 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -143,8 +143,6 @@ static void append_lost(struct sline *sline, int n, const char *line, int len) } struct combine_diff_state { - struct xdiff_emit_state xm; - unsigned int lno; int ob, on, nb, nn; unsigned long nmask; @@ -217,17 +215,15 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file, parent_file.size = sz; xpp.flags = XDF_NEED_MINIMAL; memset(&xecfg, 0, sizeof(xecfg)); - ecb.outf = xdiff_outf; - ecb.priv = &state; memset(&state, 0, sizeof(state)); - state.xm.consume = consume_line; state.nmask = nmask; state.sline = sline; state.lno = 1; state.num_parent = num_parent; state.n = n; - xdi_diff(&parent_file, result_file, &xpp, &xecfg, &ecb); + xdi_diff_outf(&parent_file, result_file, consume_line, &state, + &xpp, &xecfg, &ecb); free(parent_file.ptr); /* Assign line numbers for this parent. diff --git a/compat/mingw.c b/compat/mingw.c index 772cad510d..ccfa2a0a3d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -31,11 +31,6 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)winTime; } -static inline size_t size_to_blocks(size_t s) -{ - return (s+511)/512; -} - extern int _getdrive( void ); /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In @@ -57,10 +52,10 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_ino = 0; buf->st_gid = 0; buf->st_uid = 0; + buf->st_nlink = 1; buf->st_mode = fMode; buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_blocks = size_to_blocks(buf->st_size); - buf->st_dev = _getdrive() - 1; + buf->st_dev = buf->st_rdev = (_getdrive() - 1); buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); @@ -94,7 +89,7 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct mingw_stat *buf) +int mingw_lstat(const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; @@ -122,8 +117,7 @@ int mingw_lstat(const char *file_name, struct mingw_stat *buf) } #undef fstat -#undef stat -int mingw_fstat(int fd, struct mingw_stat *buf) +int mingw_fstat(int fd, struct stat *buf) { HANDLE fh = (HANDLE)_get_osfhandle(fd); BY_HANDLE_FILE_INFORMATION fdata; @@ -133,22 +127,8 @@ int mingw_fstat(int fd, struct mingw_stat *buf) return -1; } /* direct non-file handles to MS's fstat() */ - if (GetFileType(fh) != FILE_TYPE_DISK) { - struct stat st; - if (fstat(fd, &st)) - return -1; - buf->st_ino = st.st_ino; - buf->st_gid = st.st_gid; - buf->st_uid = st.st_uid; - buf->st_mode = st.st_mode; - buf->st_size = st.st_size; - buf->st_blocks = size_to_blocks(buf->st_size); - buf->st_dev = st.st_dev; - buf->st_atime = st.st_atime; - buf->st_mtime = st.st_mtime; - buf->st_ctime = st.st_ctime; - return 0; - } + if (GetFileType(fh) != FILE_TYPE_DISK) + return fstat(fd, buf); if (GetFileInformationByHandle(fh, &fdata)) { int fMode = S_IREAD; @@ -162,10 +142,10 @@ int mingw_fstat(int fd, struct mingw_stat *buf) buf->st_ino = 0; buf->st_gid = 0; buf->st_uid = 0; + buf->st_nlink = 1; buf->st_mode = fMode; buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_blocks = size_to_blocks(buf->st_size); - buf->st_dev = _getdrive() - 1; + buf->st_dev = buf->st_rdev = (_getdrive() - 1); buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); diff --git a/compat/mingw.h b/compat/mingw.h index a52e657c51..4f275cb8e6 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -162,22 +162,12 @@ int mingw_rename(const char*, const char*); /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. - * struct stat is redefined because it lacks the st_blocks member. */ -struct mingw_stat { - unsigned st_mode; - time_t st_mtime, st_atime, st_ctime; - unsigned st_dev, st_ino, st_uid, st_gid; - size_t st_size; - size_t st_blocks; -}; -int mingw_lstat(const char *file_name, struct mingw_stat *buf); -int mingw_fstat(int fd, struct mingw_stat *buf); +int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define stat mingw_stat -static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) -{ return mingw_lstat(file_name, buf); } +#define stat(x,y) mingw_lstat(x,y) int mingw_utime(const char *file_name, const struct utimbuf *times); #define utime mingw_utime diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 158b912841..a31004088a 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -271,15 +271,17 @@ __git_merge_strategies () echo "$__git_merge_strategylist" return fi - sed -n "/^all_strategies='/{ - s/^all_strategies='// - s/'// + git merge -s help 2>&1 | + sed -n -e '/[Aa]vailable strategies are: /,/^$/{ + s/\.$// + s/.*:// + s/^[ ]*// + s/[ ]*$// p - q - }" "$(git --exec-path)/git-merge" + }' } __git_merge_strategylist= -__git_merge_strategylist="$(__git_merge_strategies 2>/dev/null)" +__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null) __git_complete_file () { diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 3f2303dcf0..f9865b444f 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -16,6 +16,41 @@ from sets import Set; verbose = False + +def p4_build_cmd(cmd): + """Build a suitable p4 command line. + + This consolidates building and returning a p4 command line into one + location. It means that hooking into the environment, or other configuration + can be done more easily. + """ + real_cmd = "%s " % "p4" + + user = gitConfig("git-p4.user") + if len(user) > 0: + real_cmd += "-u %s " % user + + password = gitConfig("git-p4.password") + if len(password) > 0: + real_cmd += "-P %s " % password + + port = gitConfig("git-p4.port") + if len(port) > 0: + real_cmd += "-p %s " % port + + host = gitConfig("git-p4.host") + if len(host) > 0: + real_cmd += "-h %s " % host + + client = gitConfig("git-p4.client") + if len(client) > 0: + real_cmd += "-c %s " % client + + real_cmd += "%s" % (cmd) + if verbose: + print real_cmd + return real_cmd + def chdir(dir): if os.name == 'nt': os.environ['PWD']=dir @@ -39,6 +74,10 @@ def write_pipe(c, str): return val +def p4_write_pipe(c, str): + real_cmd = p4_build_cmd(c) + return write_pipe(c, str) + def read_pipe(c, ignore_error=False): if verbose: sys.stderr.write('Reading pipe: %s\n' % c) @@ -50,6 +89,9 @@ def read_pipe(c, ignore_error=False): return val +def p4_read_pipe(c, ignore_error=False): + real_cmd = p4_build_cmd(c) + return read_pipe(real_cmd, ignore_error) def read_pipe_lines(c): if verbose: @@ -62,12 +104,22 @@ def read_pipe_lines(c): return val +def p4_read_pipe_lines(c): + """Specifically invoke p4 on the command supplied. """ + real_cmd = p4_build_cmd(c) + return read_pipe_lines(real_cmd) + def system(cmd): if verbose: sys.stderr.write("executing %s\n" % cmd) if os.system(cmd) != 0: die("command failed: %s" % cmd) +def p4_system(cmd): + """Specifically invoke p4 as the system command. """ + real_cmd = p4_build_cmd(cmd) + return system(real_cmd) + def isP4Exec(kind): """Determine if a Perforce 'kind' should have execute permission @@ -89,12 +141,12 @@ def setP4ExecBit(file, mode): if p4Type[-1] == "+": p4Type = p4Type[0:-1] - system("p4 reopen -t %s %s" % (p4Type, file)) + p4_system("reopen -t %s %s" % (p4Type, file)) def getP4OpenedType(file): # Returns the perforce file type for the given file. - result = read_pipe("p4 opened %s" % file) + result = p4_read_pipe("opened %s" % file) match = re.match(".*\((.+)\)\r?$", result) if match: return match.group(1) @@ -150,7 +202,7 @@ def isModeExecChanged(src_mode, dst_mode): return isModeExec(src_mode) != isModeExec(dst_mode) def p4CmdList(cmd, stdin=None, stdin_mode='w+b'): - cmd = "p4 -G %s" % cmd + cmd = p4_build_cmd("-G %s" % (cmd)) if verbose: sys.stderr.write("Opening pipe: %s\n" % cmd) @@ -369,7 +421,7 @@ def originP4BranchesExist(): def p4ChangesForPaths(depotPaths, changeRange): assert depotPaths - output = read_pipe_lines("p4 changes " + ' '.join (["%s...%s" % (p, changeRange) + output = p4_read_pipe_lines("changes " + ' '.join (["%s...%s" % (p, changeRange) for p in depotPaths])) changes = [] @@ -517,7 +569,7 @@ class P4Submit(Command): # remove lines in the Files section that show changes to files outside the depot path we're committing into template = "" inFilesSection = False - for line in read_pipe_lines("p4 change -o"): + for line in p4_read_pipe_lines("change -o"): if line.endswith("\r\n"): line = line[:-2] + "\n" if inFilesSection: @@ -552,7 +604,7 @@ class P4Submit(Command): modifier = diff['status'] path = diff['src'] if modifier == "M": - system("p4 edit \"%s\"" % path) + p4_system("edit \"%s\"" % path) if isModeExecChanged(diff['src_mode'], diff['dst_mode']): filesToChangeExecBit[path] = diff['dst_mode'] editedFiles.add(path) @@ -567,8 +619,8 @@ class P4Submit(Command): filesToAdd.remove(path) elif modifier == "R": src, dest = diff['src'], diff['dst'] - system("p4 integrate -Dt \"%s\" \"%s\"" % (src, dest)) - system("p4 edit \"%s\"" % (dest)) + p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest)) + p4_system("edit \"%s\"" % (dest)) if isModeExecChanged(diff['src_mode'], diff['dst_mode']): filesToChangeExecBit[dest] = diff['dst_mode'] os.unlink(dest) @@ -592,7 +644,7 @@ class P4Submit(Command): if response == "s": print "Skipping! Good luck with the next patches..." for f in editedFiles: - system("p4 revert \"%s\"" % f); + p4_system("revert \"%s\"" % f); for f in filesToAdd: system("rm %s" %f) return @@ -615,10 +667,10 @@ class P4Submit(Command): system(applyPatchCmd) for f in filesToAdd: - system("p4 add \"%s\"" % f) + p4_system("add \"%s\"" % f) for f in filesToDelete: - system("p4 revert \"%s\"" % f) - system("p4 delete \"%s\"" % f) + p4_system("revert \"%s\"" % f) + p4_system("delete \"%s\"" % f) # Set/clear executable bits for f in filesToChangeExecBit.keys(): @@ -634,7 +686,7 @@ class P4Submit(Command): submitTemplate = self.prepareLogMessage(template, logMessage) if os.environ.has_key("P4DIFF"): del(os.environ["P4DIFF"]) - diff = read_pipe("p4 diff -du ...") + diff = p4_read_pipe("diff -du ...") newdiff = "" for newFile in filesToAdd: @@ -672,7 +724,7 @@ class P4Submit(Command): if self.isWindows: submitTemplate = submitTemplate.replace("\r\n", "\n") - write_pipe("p4 submit -i", submitTemplate) + p4_write_pipe("submit -i", submitTemplate) else: fileName = "submit.txt" file = open(fileName, "w+") @@ -719,7 +771,7 @@ class P4Submit(Command): chdir(self.clientPath) print "Syncronizing p4 checkout..." - system("p4 sync ...") + p4_system("sync ...") self.check() @@ -1404,7 +1456,7 @@ class P4Sync(Command): if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes and gitBranchExists(self.branch): system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch)) - if self.useClientSpec or gitConfig("p4.useclientspec") == "true": + if self.useClientSpec or gitConfig("git-p4.useclientspec") == "true": self.getClientSpec() # TODO: should always look at previous commits, diff --git a/contrib/fast-import/git-p4.txt b/contrib/fast-import/git-p4.txt index b16a8384bc..ac551d45f1 100644 --- a/contrib/fast-import/git-p4.txt +++ b/contrib/fast-import/git-p4.txt @@ -63,18 +63,6 @@ It is recommended to run 'git repack -a -d -f' from time to time when using incremental imports to optimally combine the individual git packs that each incremental import creates through the use of git-fast-import. - -A useful setup may be that you have a periodically updated git repository -somewhere that contains a complete import of a Perforce project. That git -repository can be used to clone the working repository from and one would -import from Perforce directly after cloning using git-p4. If the connection to -the Perforce server is slow and the working repository hasn't been synced for a -while it may be desirable to fetch changes from the origin git repository using -the efficient git protocol. git-p4 supports this setup by calling "git fetch origin" -by default if there is an origin branch. You can disable this using - - git config git-p4.syncFromOrigin false - Updating ======== @@ -140,6 +128,62 @@ Example git-p4 rebase +Configuration parameters +======================== + +git-p4.user ($P4USER) + +Allows you to specify the username to use to connect to the Perforce repository. + + git config [--global] git-p4.user public + +git-p4.password ($P4PASS) + +Allows you to specify the password to use to connect to the Perforce repository. +Warning this password will be visible on the command-line invocation of the p4 binary. + + git config [--global] git-p4.password public1234 + +git-p4.port ($P4PORT) + +Specify the port to be used to contact the Perforce server. As this will be passed +directly to the p4 binary, it may be in the format host:port as well. + + git config [--global] git-p4.port codes.zimbra.com:2666 + +git-p4.host ($P4HOST) + +Specify the host to contact for a Perforce repository. + + git config [--global] git-p4.host perforce.example.com + +git-p4.client ($P4CLIENT) + +Specify the client name to use + + git config [--global] git-p4.client public-view + +git-p4.allowSubmit + + git config [--global] git-p4.allowSubmit false + +git-p4.syncFromOrigin + +A useful setup may be that you have a periodically updated git repository +somewhere that contains a complete import of a Perforce project. That git +repository can be used to clone the working repository from and one would +import from Perforce directly after cloning using git-p4. If the connection to +the Perforce server is slow and the working repository hasn't been synced for a +while it may be desirable to fetch changes from the origin git repository using +the efficient git protocol. git-p4 supports this setup by calling "git fetch origin" +by default if there is an origin branch. You can disable this using: + + git config [--global] git-p4.syncFromOrigin false + +git-p4.useclientspec + + git config [--global] git-p4.useclientspec false + Implementation Details... ========================= diff --git a/decorate.c b/decorate.c index d9668d2ef9..82d9e221ea 100644 --- a/decorate.c +++ b/decorate.c @@ -6,13 +6,13 @@ #include "object.h" #include "decorate.h" -static unsigned int hash_obj(struct object *obj, unsigned int n) +static unsigned int hash_obj(const struct object *obj, unsigned int n) { unsigned int hash = *(unsigned int *)obj->sha1; return hash % n; } -static void *insert_decoration(struct decoration *n, struct object *base, void *decoration) +static void *insert_decoration(struct decoration *n, const struct object *base, void *decoration) { int size = n->size; struct object_decoration *hash = n->hash; @@ -44,7 +44,7 @@ static void grow_decoration(struct decoration *n) n->nr = 0; for (i = 0; i < old_size; i++) { - struct object *base = old_hash[i].base; + const struct object *base = old_hash[i].base; void *decoration = old_hash[i].decoration; if (!base) @@ -55,7 +55,8 @@ static void grow_decoration(struct decoration *n) } /* Add a decoration pointer, return any old one */ -void *add_decoration(struct decoration *n, struct object *obj, void *decoration) +void *add_decoration(struct decoration *n, const struct object *obj, + void *decoration) { int nr = n->nr + 1; @@ -65,7 +66,7 @@ void *add_decoration(struct decoration *n, struct object *obj, void *decoration) } /* Lookup a decoration pointer */ -void *lookup_decoration(struct decoration *n, struct object *obj) +void *lookup_decoration(struct decoration *n, const struct object *obj) { int j; diff --git a/decorate.h b/decorate.h index 1fa4ad9beb..e7328044ff 100644 --- a/decorate.h +++ b/decorate.h @@ -2,7 +2,7 @@ #define DECORATE_H struct object_decoration { - struct object *base; + const struct object *base; void *decoration; }; @@ -12,7 +12,7 @@ struct decoration { struct object_decoration *hash; }; -extern void *add_decoration(struct decoration *n, struct object *obj, void *decoration); -extern void *lookup_decoration(struct decoration *n, struct object *obj); +extern void *add_decoration(struct decoration *n, const struct object *obj, void *decoration); +extern void *lookup_decoration(struct decoration *n, const struct object *obj); #endif @@ -20,6 +20,7 @@ static int diff_detect_rename_default; static int diff_rename_limit_default = 200; +static int diff_suppress_blank_empty; int diff_use_color_default = -1; static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; @@ -176,6 +177,12 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return 0; } + /* like GNU diff's --suppress-blank-empty option */ + if (!strcmp(var, "diff.suppress-blank-empty")) { + diff_suppress_blank_empty = git_config_bool(var, value); + return 0; + } + if (!prefixcmp(var, "diff.")) { const char *ep = strrchr(var, '.'); if (ep != var + 4) { @@ -369,7 +376,6 @@ static void diff_words_append(char *line, unsigned long len, } struct diff_words_data { - struct xdiff_emit_state xm; struct diff_words_buffer minus, plus; FILE *file; }; @@ -459,11 +465,8 @@ static void diff_words_show(struct diff_words_data *diff_words) xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc; - ecb.outf = xdiff_outf; - ecb.priv = diff_words; - diff_words->xm.consume = fn_out_diff_words_aux; - xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb); - + xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, + &xpp, &xecfg, &ecb); free(minus.ptr); free(plus.ptr); diff_words->minus.text.size = diff_words->plus.text.size = 0; @@ -477,7 +480,6 @@ static void diff_words_show(struct diff_words_data *diff_words) typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); struct emit_callback { - struct xdiff_emit_state xm; int nparents, color_diff; unsigned ws_rule; sane_truncate_fn truncate; @@ -580,6 +582,12 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) ecbdata->label_path[0] = ecbdata->label_path[1] = NULL; } + if (diff_suppress_blank_empty + && len == 2 && line[0] == ' ' && line[1] == '\n') { + line[0] = '\n'; + len = 1; + } + /* This is not really necessary for now because * this codepath only deals with two-way diffs. */ @@ -708,8 +716,6 @@ static char *pprint_rename(const char *a, const char *b) } struct diffstat_t { - struct xdiff_emit_state xm; - int nr; int alloc; struct diffstat_file { @@ -1131,7 +1137,6 @@ static void free_diffstat_info(struct diffstat_t *diffstat) } struct checkdiff_t { - struct xdiff_emit_state xm; const char *filename; int lineno; struct diff_options *o; @@ -1521,15 +1526,13 @@ static void builtin_diff(const char *name_a, xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10); else if (!prefixcmp(diffopts, "-u")) xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10); - ecb.outf = xdiff_outf; - ecb.priv = &ecbdata; - ecbdata.xm.consume = fn_out_consume; if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) { ecbdata.diff_words = xcalloc(1, sizeof(struct diff_words_data)); ecbdata.diff_words->file = o->file; } - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, + &xpp, &xecfg, &ecb); if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) free_diff_words_data(&ecbdata); } @@ -1580,9 +1583,8 @@ static void builtin_diffstat(const char *name_a, const char *name_b, memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; - ecb.outf = xdiff_outf; - ecb.priv = diffstat; - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat, + &xpp, &xecfg, &ecb); } free_and_return: @@ -1603,7 +1605,6 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, return; memset(&data, 0, sizeof(data)); - data.xm.consume = checkdiff_consume; data.filename = name_b ? name_b : name_a; data.lineno = 0; data.o = o; @@ -1627,10 +1628,10 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, xdemitcb_t ecb; memset(&xecfg, 0, sizeof(xecfg)); + xecfg.ctxlen = 1; /* at least one context line */ xpp.flags = XDF_NEED_MINIMAL; - ecb.outf = xdiff_outf; - ecb.priv = &data; - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data, + &xpp, &xecfg, &ecb); if ((data.ws_rule & WS_TRAILING_SPACE) && data.trailing_blanks_start) { @@ -3018,7 +3019,6 @@ static void diff_summary(FILE *file, struct diff_filepair *p) } struct patch_id_t { - struct xdiff_emit_state xm; SHA_CTX *ctx; int patchlen; }; @@ -3063,7 +3063,6 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) SHA1_Init(&ctx); memset(&data, 0, sizeof(struct patch_id_t)); data.ctx = &ctx; - data.xm.consume = patch_id_consume; for (i = 0; i < q->nr; i++) { xpparam_t xpp; @@ -3128,9 +3127,8 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = 3; xecfg.flags = XDL_EMIT_FUNCNAMES; - ecb.outf = xdiff_outf; - ecb.priv = &data; - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data, + &xpp, &xecfg, &ecb); } SHA1_Final(sha1, &ctx); @@ -3207,7 +3205,6 @@ void diff_flush(struct diff_options *options) struct diffstat_t diffstat; memset(&diffstat, 0, sizeof(struct diffstat_t)); - diffstat.xm.consume = diffstat_consume; for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; if (check_pair_status(p)) diff --git a/git-compat-util.h b/git-compat-util.h index cf89cdf459..6ee325546e 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -99,6 +99,11 @@ #include <iconv.h> #endif +#ifndef NO_OPENSSL +#include <openssl/ssl.h> +#include <openssl/err.h> +#endif + /* On most systems <limits.h> would have given us this, but * not on some systems (e.g. GNU/Hurd). */ @@ -192,6 +197,12 @@ extern int git_munmap(void *start, size_t length); #endif /* NO_MMAP */ +#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT +#define on_disk_bytes(st) ((st).st_size) +#else +#define on_disk_bytes(st) ((st).st_blocks * 512) +#endif + #define DEFAULT_PACKED_GIT_LIMIT \ ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256)) diff --git a/git-gui/GIT-VERSION-GEN b/git-gui/GIT-VERSION-GEN index 0ab478ef90..4e709ebe77 100755 --- a/git-gui/GIT-VERSION-GEN +++ b/git-gui/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=0.10.GITGUI +DEF_VER=0.11.GITGUI LF=' ' diff --git a/hash-object.c b/hash-object.c index 46c06a9552..a4d127cf78 100644 --- a/hash-object.c +++ b/hash-object.c @@ -7,16 +7,14 @@ #include "cache.h" #include "blob.h" #include "quote.h" +#include "parse-options.h" -static void hash_object(const char *path, enum object_type type, int write_object) +static void hash_fd(int fd, const char *type, int write_object, const char *path) { - int fd; struct stat st; unsigned char sha1[20]; - fd = open(path, O_RDONLY); - if (fd < 0 || - fstat(fd, &st) < 0 || - index_fd(sha1, fd, &st, write_object, type, path)) + if (fstat(fd, &st) < 0 || + index_fd(sha1, fd, &st, write_object, type_from_string(type), path)) die(write_object ? "Unable to add %s to database" : "Unable to hash %s", path); @@ -24,12 +22,14 @@ static void hash_object(const char *path, enum object_type type, int write_objec maybe_flush_or_die(stdout, "hash to stdout"); } -static void hash_stdin(const char *type, int write_object) +static void hash_object(const char *path, const char *type, int write_object, + const char *vpath) { - unsigned char sha1[20]; - if (index_pipe(sha1, 0, type, write_object)) - die("Unable to add stdin to database"); - printf("%s\n", sha1_to_hex(sha1)); + int fd; + fd = open(path, O_RDONLY); + if (fd < 0) + die("Cannot open %s", path); + hash_fd(fd, type, write_object, vpath); } static void hash_stdin_paths(const char *type, int write_objects) @@ -45,92 +45,91 @@ static void hash_stdin_paths(const char *type, int write_objects) die("line is badly quoted"); strbuf_swap(&buf, &nbuf); } - hash_object(buf.buf, type_from_string(type), write_objects); + hash_object(buf.buf, type, write_objects, buf.buf); } strbuf_release(&buf); strbuf_release(&nbuf); } -static const char hash_object_usage[] = -"git hash-object [ [-t <type>] [-w] [--stdin] <file>... | --stdin-paths < <list-of-paths> ]"; +static const char * const hash_object_usage[] = { + "git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>...", + "git hash-object --stdin-paths < <list-of-paths>", + NULL +}; -int main(int argc, char **argv) +static const char *type; +static int write_object; +static int hashstdin; +static int stdin_paths; +static int no_filters; +static const char *vpath; + +static const struct option hash_object_options[] = { + OPT_STRING('t', NULL, &type, "type", "object type"), + OPT_BOOLEAN('w', NULL, &write_object, "write the object into the object database"), + OPT_BOOLEAN( 0 , "stdin", &hashstdin, "read the object from stdin"), + OPT_BOOLEAN( 0 , "stdin-paths", &stdin_paths, "read file names from stdin"), + OPT_BOOLEAN( 0 , "no-filters", &no_filters, "store file as is without filters"), + OPT_STRING( 0 , "path", &vpath, "file", "process file as it were from this path"), + OPT_END() +}; + +int main(int argc, const char **argv) { int i; - const char *type = blob_type; - int write_object = 0; const char *prefix = NULL; int prefix_length = -1; - int no_more_flags = 0; - int hashstdin = 0; - int stdin_paths = 0; + const char *errstr = NULL; + + type = blob_type; git_config(git_default_config, NULL); - for (i = 1 ; i < argc; i++) { - if (!no_more_flags && argv[i][0] == '-') { - if (!strcmp(argv[i], "-t")) { - if (argc <= ++i) - usage(hash_object_usage); - type = argv[i]; - } - else if (!strcmp(argv[i], "-w")) { - if (prefix_length < 0) { - prefix = setup_git_directory(); - prefix_length = - prefix ? strlen(prefix) : 0; - } - write_object = 1; - } - else if (!strcmp(argv[i], "--")) { - no_more_flags = 1; - } - else if (!strcmp(argv[i], "--help")) - usage(hash_object_usage); - else if (!strcmp(argv[i], "--stdin-paths")) { - if (hashstdin) { - error("Can't use --stdin-paths with --stdin"); - usage(hash_object_usage); - } - stdin_paths = 1; - - } - else if (!strcmp(argv[i], "--stdin")) { - if (stdin_paths) { - error("Can't use %s with --stdin-paths", argv[i]); - usage(hash_object_usage); - } - if (hashstdin) - die("Multiple --stdin arguments are not supported"); - hashstdin = 1; - } - else - usage(hash_object_usage); - } - else { - const char *arg = argv[i]; - - if (stdin_paths) { - error("Can't specify files (such as \"%s\") with --stdin-paths", arg); - usage(hash_object_usage); - } - - if (hashstdin) { - hash_stdin(type, write_object); - hashstdin = 0; - } - if (0 <= prefix_length) - arg = prefix_filename(prefix, prefix_length, - arg); - hash_object(arg, type_from_string(type), write_object); - no_more_flags = 1; - } + argc = parse_options(argc, argv, hash_object_options, hash_object_usage, 0); + + if (write_object) { + prefix = setup_git_directory(); + prefix_length = prefix ? strlen(prefix) : 0; + if (vpath && prefix) + vpath = prefix_filename(prefix, prefix_length, vpath); + } + + if (stdin_paths) { + if (hashstdin) + errstr = "Can't use --stdin-paths with --stdin"; + else if (argc) + errstr = "Can't specify files with --stdin-paths"; + else if (vpath) + errstr = "Can't use --stdin-paths with --path"; + else if (no_filters) + errstr = "Can't use --stdin-paths with --no-filters"; + } + else { + if (hashstdin > 1) + errstr = "Multiple --stdin arguments are not supported"; + if (vpath && no_filters) + errstr = "Can't use --path with --no-filters"; + } + + if (errstr) { + error (errstr); + usage_with_options(hash_object_usage, hash_object_options); + } + + if (hashstdin) + hash_fd(0, type, write_object, vpath); + + for (i = 0 ; i < argc; i++) { + const char *arg = argv[i]; + + if (0 <= prefix_length) + arg = prefix_filename(prefix, prefix_length, arg); + hash_object(arg, type, write_object, + no_filters ? NULL : vpath ? vpath : arg); } if (stdin_paths) hash_stdin_paths(type, write_object); - if (hashstdin) - hash_stdin(type, write_object); return 0; } diff --git a/imap-send.c b/imap-send.c index 1ec1310921..af7e08c094 100644 --- a/imap-send.c +++ b/imap-send.c @@ -23,71 +23,74 @@ */ #include "cache.h" +#ifdef NO_OPENSSL +typedef void *SSL; +#endif -typedef struct store_conf { +struct store_conf { char *name; const char *path; /* should this be here? its interpretation is driver-specific */ char *map_inbox; char *trash; unsigned max_size; /* off_t is overkill */ unsigned trash_remote_new:1, trash_only_new:1; -} store_conf_t; +}; -typedef struct string_list { +struct string_list { struct string_list *next; char string[1]; -} string_list_t; +}; -typedef struct channel_conf { +struct channel_conf { struct channel_conf *next; char *name; - store_conf_t *master, *slave; + struct store_conf *master, *slave; char *master_name, *slave_name; char *sync_state; - string_list_t *patterns; + struct string_list *patterns; int mops, sops; unsigned max_messages; /* for slave only */ -} channel_conf_t; +}; -typedef struct group_conf { +struct group_conf { struct group_conf *next; char *name; - string_list_t *channels; -} group_conf_t; + struct string_list *channels; +}; /* For message->status */ #define M_RECENT (1<<0) /* unsyncable flag; maildir_* depend on this being 1<<0 */ #define M_DEAD (1<<1) /* expunged */ #define M_FLAGS (1<<2) /* flags fetched */ -typedef struct message { +struct message { struct message *next; - /* string_list_t *keywords; */ + /* struct string_list *keywords; */ size_t size; /* zero implies "not fetched" */ int uid; unsigned char flags, status; -} message_t; +}; -typedef struct store { - store_conf_t *conf; /* foreign */ +struct store { + struct store_conf *conf; /* foreign */ /* currently open mailbox */ const char *name; /* foreign! maybe preset? */ char *path; /* own */ - message_t *msgs; /* own */ + struct message *msgs; /* own */ int uidvalidity; unsigned char opts; /* maybe preset? */ /* note that the following do _not_ reflect stats from msgs, but mailbox totals */ int count; /* # of messages */ int recent; /* # of recent messages - don't trust this beyond the initial read */ -} store_t; +}; -typedef struct { +struct msg_data { char *data; int len; unsigned char flags; unsigned int crlf:1; -} msg_data_t; +}; #define DRV_OK 0 #define DRV_MSG_BAD -1 @@ -96,14 +99,14 @@ typedef struct { static int Verbose, Quiet; -static void imap_info( const char *, ... ); -static void imap_warn( const char *, ... ); +static void imap_info(const char *, ...); +static void imap_warn(const char *, ...); -static char *next_arg( char ** ); +static char *next_arg(char **); -static void free_generic_messages( message_t * ); +static void free_generic_messages(struct message *); -static int nfsnprintf( char *buf, int blen, const char *fmt, ... ); +static int nfsnprintf(char *buf, int blen, const char *fmt, ...); static int nfvasprintf(char **strp, const char *fmt, va_list ap) { @@ -119,67 +122,70 @@ static int nfvasprintf(char **strp, const char *fmt, va_list ap) return len; } -static void arc4_init( void ); -static unsigned char arc4_getbyte( void ); +static void arc4_init(void); +static unsigned char arc4_getbyte(void); -typedef struct imap_server_conf { +struct imap_server_conf { char *name; char *tunnel; char *host; int port; char *user; char *pass; -} imap_server_conf_t; + int use_ssl; + int ssl_verify; +}; -typedef struct imap_store_conf { - store_conf_t gen; - imap_server_conf_t *server; +struct imap_store_conf { + struct store_conf gen; + struct imap_server_conf *server; unsigned use_namespace:1; -} imap_store_conf_t; +}; -#define NIL (void*)0x1 -#define LIST (void*)0x2 +#define NIL (void *)0x1 +#define LIST (void *)0x2 -typedef struct _list { - struct _list *next, *child; +struct imap_list { + struct imap_list *next, *child; char *val; int len; -} list_t; +}; -typedef struct { +struct imap_socket { int fd; -} Socket_t; + SSL *ssl; +}; -typedef struct { - Socket_t sock; +struct imap_buffer { + struct imap_socket sock; int bytes; int offset; char buf[1024]; -} buffer_t; +}; struct imap_cmd; -typedef struct imap { +struct imap { int uidnext; /* from SELECT responses */ - list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */ + struct imap_list *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */ unsigned caps, rcaps; /* CAPABILITY results */ /* command queue */ int nexttag, num_in_progress, literal_pending; struct imap_cmd *in_progress, **in_progress_append; - buffer_t buf; /* this is BIG, so put it last */ -} imap_t; + struct imap_buffer buf; /* this is BIG, so put it last */ +}; -typedef struct imap_store { - store_t gen; +struct imap_store { + struct store gen; int uidvalidity; - imap_t *imap; + struct imap *imap; const char *prefix; unsigned /*currentnc:1,*/ trashnc:1; -} imap_store_t; +}; struct imap_cmd_cb { - int (*cont)( imap_store_t *ctx, struct imap_cmd *cmd, const char *prompt ); - void (*done)( imap_store_t *ctx, struct imap_cmd *cmd, int response); + int (*cont)(struct imap_store *ctx, struct imap_cmd *cmd, const char *prompt); + void (*done)(struct imap_store *ctx, struct imap_cmd *cmd, int response); void *ctx; char *data; int dlen; @@ -201,6 +207,7 @@ enum CAPABILITY { UIDPLUS, LITERALPLUS, NAMESPACE, + STARTTLS, }; static const char *cap_list[] = { @@ -208,13 +215,14 @@ static const char *cap_list[] = { "UIDPLUS", "LITERAL+", "NAMESPACE", + "STARTTLS", }; #define RESP_OK 0 #define RESP_NO 1 #define RESP_BAD 2 -static int get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ); +static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd); static const char *Flags[] = { @@ -225,42 +233,137 @@ static const char *Flags[] = { "Deleted", }; -static void -socket_perror( const char *func, Socket_t *sock, int ret ) +#ifndef NO_OPENSSL +static void ssl_socket_perror(const char *func) +{ + fprintf(stderr, "%s: %s\n", func, ERR_error_string(ERR_get_error(), 0)); +} +#endif + +static void socket_perror(const char *func, struct imap_socket *sock, int ret) +{ +#ifndef NO_OPENSSL + if (sock->ssl) { + int sslerr = SSL_get_error(sock->ssl, ret); + switch (sslerr) { + case SSL_ERROR_NONE: + break; + case SSL_ERROR_SYSCALL: + perror("SSL_connect"); + break; + default: + ssl_socket_perror("SSL_connect"); + break; + } + } else +#endif + { + if (ret < 0) + perror(func); + else + fprintf(stderr, "%s: unexpected EOF\n", func); + } +} + +static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify) { - if (ret < 0) - perror( func ); +#ifdef NO_OPENSSL + fprintf(stderr, "SSL requested but SSL support not compiled in\n"); + return -1; +#else + SSL_METHOD *meth; + SSL_CTX *ctx; + int ret; + + SSL_library_init(); + SSL_load_error_strings(); + + if (use_tls_only) + meth = TLSv1_method(); else - fprintf( stderr, "%s: unexpected EOF\n", func ); + meth = SSLv23_method(); + + if (!meth) { + ssl_socket_perror("SSLv23_method"); + return -1; + } + + ctx = SSL_CTX_new(meth); + + if (verify) + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + + if (!SSL_CTX_set_default_verify_paths(ctx)) { + ssl_socket_perror("SSL_CTX_set_default_verify_paths"); + return -1; + } + sock->ssl = SSL_new(ctx); + if (!sock->ssl) { + ssl_socket_perror("SSL_new"); + return -1; + } + if (!SSL_set_fd(sock->ssl, sock->fd)) { + ssl_socket_perror("SSL_set_fd"); + return -1; + } + + ret = SSL_connect(sock->ssl); + if (ret <= 0) { + socket_perror("SSL_connect", sock, ret); + return -1; + } + + return 0; +#endif } -static int -socket_read( Socket_t *sock, char *buf, int len ) +static int socket_read(struct imap_socket *sock, char *buf, int len) { - ssize_t n = xread( sock->fd, buf, len ); + ssize_t n; +#ifndef NO_OPENSSL + if (sock->ssl) + n = SSL_read(sock->ssl, buf, len); + else +#endif + n = xread(sock->fd, buf, len); if (n <= 0) { - socket_perror( "read", sock, n ); - close( sock->fd ); + socket_perror("read", sock, n); + close(sock->fd); sock->fd = -1; } return n; } -static int -socket_write( Socket_t *sock, const char *buf, int len ) +static int socket_write(struct imap_socket *sock, const char *buf, int len) { - int n = write_in_full( sock->fd, buf, len ); + int n; +#ifndef NO_OPENSSL + if (sock->ssl) + n = SSL_write(sock->ssl, buf, len); + else +#endif + n = write_in_full(sock->fd, buf, len); if (n != len) { - socket_perror( "write", sock, n ); - close( sock->fd ); + socket_perror("write", sock, n); + close(sock->fd); sock->fd = -1; } return n; } +static void socket_shutdown(struct imap_socket *sock) +{ +#ifndef NO_OPENSSL + if (sock->ssl) { + SSL_shutdown(sock->ssl); + SSL_free(sock->ssl); + } +#endif + close(sock->fd); +} + /* simple line buffering */ -static int -buffer_gets( buffer_t * b, char **s ) +static int buffer_gets(struct imap_buffer *b, char **s) { int n; int start = b->offset; @@ -274,7 +377,7 @@ buffer_gets( buffer_t * b, char **s ) /* shift down used bytes */ *s = b->buf; - assert( start <= b->bytes ); + assert(start <= b->bytes); n = b->bytes - start; if (n) @@ -284,8 +387,8 @@ buffer_gets( buffer_t * b, char **s ) start = 0; } - n = socket_read( &b->sock, b->buf + b->bytes, - sizeof(b->buf) - b->bytes ); + n = socket_read(&b->sock, b->buf + b->bytes, + sizeof(b->buf) - b->bytes); if (n <= 0) return -1; @@ -294,12 +397,12 @@ buffer_gets( buffer_t * b, char **s ) } if (b->buf[b->offset] == '\r') { - assert( b->offset + 1 < b->bytes ); + assert(b->offset + 1 < b->bytes); if (b->buf[b->offset + 1] == '\n') { b->buf[b->offset] = 0; /* terminate the string */ b->offset += 2; /* next line */ if (Verbose) - puts( *s ); + puts(*s); return 0; } } @@ -309,39 +412,36 @@ buffer_gets( buffer_t * b, char **s ) /* not reached */ } -static void -imap_info( const char *msg, ... ) +static void imap_info(const char *msg, ...) { va_list va; if (!Quiet) { - va_start( va, msg ); - vprintf( msg, va ); - va_end( va ); - fflush( stdout ); + va_start(va, msg); + vprintf(msg, va); + va_end(va); + fflush(stdout); } } -static void -imap_warn( const char *msg, ... ) +static void imap_warn(const char *msg, ...) { va_list va; if (Quiet < 2) { - va_start( va, msg ); - vfprintf( stderr, msg, va ); - va_end( va ); + va_start(va, msg); + vfprintf(stderr, msg, va); + va_end(va); } } -static char * -next_arg( char **s ) +static char *next_arg(char **s) { char *ret; if (!s || !*s) return NULL; - while (isspace( (unsigned char) **s )) + while (isspace((unsigned char) **s)) (*s)++; if (!**s) { *s = NULL; @@ -350,10 +450,10 @@ next_arg( char **s ) if (**s == '"') { ++*s; ret = *s; - *s = strchr( *s, '"' ); + *s = strchr(*s, '"'); } else { ret = *s; - while (**s && !isspace( (unsigned char) **s )) + while (**s && !isspace((unsigned char) **s)) (*s)++; } if (*s) { @@ -365,27 +465,25 @@ next_arg( char **s ) return ret; } -static void -free_generic_messages( message_t *msgs ) +static void free_generic_messages(struct message *msgs) { - message_t *tmsg; + struct message *tmsg; for (; msgs; msgs = tmsg) { tmsg = msgs->next; - free( msgs ); + free(msgs); } } -static int -nfsnprintf( char *buf, int blen, const char *fmt, ... ) +static int nfsnprintf(char *buf, int blen, const char *fmt, ...) { int ret; va_list va; - va_start( va, fmt ); - if (blen <= 0 || (unsigned)(ret = vsnprintf( buf, blen, fmt, va )) >= (unsigned)blen) - die( "Fatal: buffer too small. Please report a bug.\n"); - va_end( va ); + va_start(va, fmt); + if (blen <= 0 || (unsigned)(ret = vsnprintf(buf, blen, fmt, va)) >= (unsigned)blen) + die("Fatal: buffer too small. Please report a bug.\n"); + va_end(va); return ret; } @@ -393,21 +491,20 @@ static struct { unsigned char i, j, s[256]; } rs; -static void -arc4_init( void ) +static void arc4_init(void) { int i, fd; unsigned char j, si, dat[128]; - if ((fd = open( "/dev/urandom", O_RDONLY )) < 0 && (fd = open( "/dev/random", O_RDONLY )) < 0) { - fprintf( stderr, "Fatal: no random number source available.\n" ); - exit( 3 ); + if ((fd = open("/dev/urandom", O_RDONLY)) < 0 && (fd = open("/dev/random", O_RDONLY)) < 0) { + fprintf(stderr, "Fatal: no random number source available.\n"); + exit(3); } - if (read_in_full( fd, dat, 128 ) != 128) { - fprintf( stderr, "Fatal: cannot read random number source.\n" ); - exit( 3 ); + if (read_in_full(fd, dat, 128) != 128) { + fprintf(stderr, "Fatal: cannot read random number source.\n"); + exit(3); } - close( fd ); + close(fd); for (i = 0; i < 256; i++) rs.s[i] = i; @@ -423,8 +520,7 @@ arc4_init( void ) arc4_getbyte(); } -static unsigned char -arc4_getbyte( void ) +static unsigned char arc4_getbyte(void) { unsigned char si, sj; @@ -437,54 +533,53 @@ arc4_getbyte( void ) return rs.s[(si + sj) & 0xff]; } -static struct imap_cmd * -v_issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb, - const char *fmt, va_list ap ) +static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx, + struct imap_cmd_cb *cb, + const char *fmt, va_list ap) { - imap_t *imap = ctx->imap; + struct imap *imap = ctx->imap; struct imap_cmd *cmd; int n, bufl; char buf[1024]; - cmd = xmalloc( sizeof(struct imap_cmd) ); - nfvasprintf( &cmd->cmd, fmt, ap ); + cmd = xmalloc(sizeof(struct imap_cmd)); + nfvasprintf(&cmd->cmd, fmt, ap); cmd->tag = ++imap->nexttag; if (cb) cmd->cb = *cb; else - memset( &cmd->cb, 0, sizeof(cmd->cb) ); + memset(&cmd->cb, 0, sizeof(cmd->cb)); while (imap->literal_pending) - get_cmd_result( ctx, NULL ); + get_cmd_result(ctx, NULL); - bufl = nfsnprintf( buf, sizeof(buf), cmd->cb.data ? CAP(LITERALPLUS) ? + bufl = nfsnprintf(buf, sizeof(buf), cmd->cb.data ? CAP(LITERALPLUS) ? "%d %s{%d+}\r\n" : "%d %s{%d}\r\n" : "%d %s\r\n", - cmd->tag, cmd->cmd, cmd->cb.dlen ); + cmd->tag, cmd->cmd, cmd->cb.dlen); if (Verbose) { if (imap->num_in_progress) - printf( "(%d in progress) ", imap->num_in_progress ); - if (memcmp( cmd->cmd, "LOGIN", 5 )) - printf( ">>> %s", buf ); + printf("(%d in progress) ", imap->num_in_progress); + if (memcmp(cmd->cmd, "LOGIN", 5)) + printf(">>> %s", buf); else - printf( ">>> %d LOGIN <user> <pass>\n", cmd->tag ); + printf(">>> %d LOGIN <user> <pass>\n", cmd->tag); } - if (socket_write( &imap->buf.sock, buf, bufl ) != bufl) { - free( cmd->cmd ); - free( cmd ); + if (socket_write(&imap->buf.sock, buf, bufl) != bufl) { + free(cmd->cmd); + free(cmd); if (cb) - free( cb->data ); + free(cb->data); return NULL; } if (cmd->cb.data) { if (CAP(LITERALPLUS)) { - n = socket_write( &imap->buf.sock, cmd->cb.data, cmd->cb.dlen ); - free( cmd->cb.data ); + n = socket_write(&imap->buf.sock, cmd->cb.data, cmd->cb.dlen); + free(cmd->cb.data); if (n != cmd->cb.dlen || - (n = socket_write( &imap->buf.sock, "\r\n", 2 )) != 2) - { - free( cmd->cmd ); - free( cmd ); + (n = socket_write(&imap->buf.sock, "\r\n", 2)) != 2) { + free(cmd->cmd); + free(cmd); return NULL; } cmd->cb.data = NULL; @@ -499,109 +594,106 @@ v_issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb, return cmd; } -static struct imap_cmd * -issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) +static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx, + struct imap_cmd_cb *cb, + const char *fmt, ...) { struct imap_cmd *ret; va_list ap; - va_start( ap, fmt ); - ret = v_issue_imap_cmd( ctx, cb, fmt, ap ); - va_end( ap ); + va_start(ap, fmt); + ret = v_issue_imap_cmd(ctx, cb, fmt, ap); + va_end(ap); return ret; } -static int -imap_exec( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) +static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb, + const char *fmt, ...) { va_list ap; struct imap_cmd *cmdp; - va_start( ap, fmt ); - cmdp = v_issue_imap_cmd( ctx, cb, fmt, ap ); - va_end( ap ); + va_start(ap, fmt); + cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap); + va_end(ap); if (!cmdp) return RESP_BAD; - return get_cmd_result( ctx, cmdp ); + return get_cmd_result(ctx, cmdp); } -static int -imap_exec_m( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) +static int imap_exec_m(struct imap_store *ctx, struct imap_cmd_cb *cb, + const char *fmt, ...) { va_list ap; struct imap_cmd *cmdp; - va_start( ap, fmt ); - cmdp = v_issue_imap_cmd( ctx, cb, fmt, ap ); - va_end( ap ); + va_start(ap, fmt); + cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap); + va_end(ap); if (!cmdp) return DRV_STORE_BAD; - switch (get_cmd_result( ctx, cmdp )) { + switch (get_cmd_result(ctx, cmdp)) { case RESP_BAD: return DRV_STORE_BAD; case RESP_NO: return DRV_MSG_BAD; default: return DRV_OK; } } -static int -is_atom( list_t *list ) +static int is_atom(struct imap_list *list) { return list && list->val && list->val != NIL && list->val != LIST; } -static int -is_list( list_t *list ) +static int is_list(struct imap_list *list) { return list && list->val == LIST; } -static void -free_list( list_t *list ) +static void free_list(struct imap_list *list) { - list_t *tmp; + struct imap_list *tmp; for (; list; list = tmp) { tmp = list->next; - if (is_list( list )) - free_list( list->child ); - else if (is_atom( list )) - free( list->val ); - free( list ); + if (is_list(list)) + free_list(list->child); + else if (is_atom(list)) + free(list->val); + free(list); } } -static int -parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level ) +static int parse_imap_list_l(struct imap *imap, char **sp, struct imap_list **curp, int level) { - list_t *cur; + struct imap_list *cur; char *s = *sp, *p; int n, bytes; for (;;) { - while (isspace( (unsigned char)*s )) + while (isspace((unsigned char)*s)) s++; if (level && *s == ')') { s++; break; } - *curp = cur = xmalloc( sizeof(*cur) ); + *curp = cur = xmalloc(sizeof(*cur)); curp = &cur->next; cur->val = NULL; /* for clean bail */ if (*s == '(') { /* sublist */ s++; cur->val = LIST; - if (parse_imap_list_l( imap, &s, &cur->child, level + 1 )) + if (parse_imap_list_l(imap, &s, &cur->child, level + 1)) goto bail; } else if (imap && *s == '{') { /* literal */ - bytes = cur->len = strtol( s + 1, &s, 10 ); + bytes = cur->len = strtol(s + 1, &s, 10); if (*s != '}') goto bail; - s = cur->val = xmalloc( cur->len ); + s = cur->val = xmalloc(cur->len); /* dump whats left over in the input buffer */ n = imap->buf.bytes - imap->buf.offset; @@ -610,7 +702,7 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level ) /* the entire message fit in the buffer */ n = bytes; - memcpy( s, imap->buf.buf + imap->buf.offset, n ); + memcpy(s, imap->buf.buf + imap->buf.offset, n); s += n; bytes -= n; @@ -619,13 +711,13 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level ) /* now read the rest of the message */ while (bytes > 0) { - if ((n = socket_read (&imap->buf.sock, s, bytes)) <= 0) + if ((n = socket_read(&imap->buf.sock, s, bytes)) <= 0) goto bail; s += n; bytes -= n; } - if (buffer_gets( &imap->buf, &s )) + if (buffer_gets(&imap->buf, &s)) goto bail; } else if (*s == '"') { /* quoted string */ @@ -640,15 +732,14 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level ) } else { /* atom */ p = s; - for (; *s && !isspace( (unsigned char)*s ); s++) + for (; *s && !isspace((unsigned char)*s); s++) if (level && *s == ')') break; cur->len = s - p; - if (cur->len == 3 && !memcmp ("NIL", p, 3)) { + if (cur->len == 3 && !memcmp("NIL", p, 3)) cur->val = NIL; - } else { + else cur->val = xmemdupz(p, cur->len); - } } if (!level) @@ -660,127 +751,122 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level ) *curp = NULL; return 0; - bail: +bail: *curp = NULL; return -1; } -static list_t * -parse_imap_list( imap_t *imap, char **sp ) +static struct imap_list *parse_imap_list(struct imap *imap, char **sp) { - list_t *head; + struct imap_list *head; - if (!parse_imap_list_l( imap, sp, &head, 0 )) + if (!parse_imap_list_l(imap, sp, &head, 0)) return head; - free_list( head ); + free_list(head); return NULL; } -static list_t * -parse_list( char **sp ) +static struct imap_list *parse_list(char **sp) { - return parse_imap_list( NULL, sp ); + return parse_imap_list(NULL, sp); } -static void -parse_capability( imap_t *imap, char *cmd ) +static void parse_capability(struct imap *imap, char *cmd) { char *arg; unsigned i; imap->caps = 0x80000000; - while ((arg = next_arg( &cmd ))) + while ((arg = next_arg(&cmd))) for (i = 0; i < ARRAY_SIZE(cap_list); i++) - if (!strcmp( cap_list[i], arg )) + if (!strcmp(cap_list[i], arg)) imap->caps |= 1 << i; imap->rcaps = imap->caps; } -static int -parse_response_code( imap_store_t *ctx, struct imap_cmd_cb *cb, char *s ) +static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb, + char *s) { - imap_t *imap = ctx->imap; + struct imap *imap = ctx->imap; char *arg, *p; if (*s != '[') return RESP_OK; /* no response code */ s++; - if (!(p = strchr( s, ']' ))) { - fprintf( stderr, "IMAP error: malformed response code\n" ); + if (!(p = strchr(s, ']'))) { + fprintf(stderr, "IMAP error: malformed response code\n"); return RESP_BAD; } *p++ = 0; - arg = next_arg( &s ); - if (!strcmp( "UIDVALIDITY", arg )) { - if (!(arg = next_arg( &s )) || !(ctx->gen.uidvalidity = atoi( arg ))) { - fprintf( stderr, "IMAP error: malformed UIDVALIDITY status\n" ); + arg = next_arg(&s); + if (!strcmp("UIDVALIDITY", arg)) { + if (!(arg = next_arg(&s)) || !(ctx->gen.uidvalidity = atoi(arg))) { + fprintf(stderr, "IMAP error: malformed UIDVALIDITY status\n"); return RESP_BAD; } - } else if (!strcmp( "UIDNEXT", arg )) { - if (!(arg = next_arg( &s )) || !(imap->uidnext = atoi( arg ))) { - fprintf( stderr, "IMAP error: malformed NEXTUID status\n" ); + } else if (!strcmp("UIDNEXT", arg)) { + if (!(arg = next_arg(&s)) || !(imap->uidnext = atoi(arg))) { + fprintf(stderr, "IMAP error: malformed NEXTUID status\n"); return RESP_BAD; } - } else if (!strcmp( "CAPABILITY", arg )) { - parse_capability( imap, s ); - } else if (!strcmp( "ALERT", arg )) { + } else if (!strcmp("CAPABILITY", arg)) { + parse_capability(imap, s); + } else if (!strcmp("ALERT", arg)) { /* RFC2060 says that these messages MUST be displayed * to the user */ - for (; isspace( (unsigned char)*p ); p++); - fprintf( stderr, "*** IMAP ALERT *** %s\n", p ); - } else if (cb && cb->ctx && !strcmp( "APPENDUID", arg )) { - if (!(arg = next_arg( &s )) || !(ctx->gen.uidvalidity = atoi( arg )) || - !(arg = next_arg( &s )) || !(*(int *)cb->ctx = atoi( arg ))) - { - fprintf( stderr, "IMAP error: malformed APPENDUID status\n" ); + for (; isspace((unsigned char)*p); p++); + fprintf(stderr, "*** IMAP ALERT *** %s\n", p); + } else if (cb && cb->ctx && !strcmp("APPENDUID", arg)) { + if (!(arg = next_arg(&s)) || !(ctx->gen.uidvalidity = atoi(arg)) || + !(arg = next_arg(&s)) || !(*(int *)cb->ctx = atoi(arg))) { + fprintf(stderr, "IMAP error: malformed APPENDUID status\n"); return RESP_BAD; } } return RESP_OK; } -static int -get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) +static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd) { - imap_t *imap = ctx->imap; + struct imap *imap = ctx->imap; struct imap_cmd *cmdp, **pcmdp, *ncmdp; char *cmd, *arg, *arg1, *p; int n, resp, resp2, tag; for (;;) { - if (buffer_gets( &imap->buf, &cmd )) + if (buffer_gets(&imap->buf, &cmd)) return RESP_BAD; - arg = next_arg( &cmd ); + arg = next_arg(&cmd); if (*arg == '*') { - arg = next_arg( &cmd ); + arg = next_arg(&cmd); if (!arg) { - fprintf( stderr, "IMAP error: unable to parse untagged response\n" ); + fprintf(stderr, "IMAP error: unable to parse untagged response\n"); return RESP_BAD; } - if (!strcmp( "NAMESPACE", arg )) { - imap->ns_personal = parse_list( &cmd ); - imap->ns_other = parse_list( &cmd ); - imap->ns_shared = parse_list( &cmd ); - } else if (!strcmp( "OK", arg ) || !strcmp( "BAD", arg ) || - !strcmp( "NO", arg ) || !strcmp( "BYE", arg )) { - if ((resp = parse_response_code( ctx, NULL, cmd )) != RESP_OK) + if (!strcmp("NAMESPACE", arg)) { + imap->ns_personal = parse_list(&cmd); + imap->ns_other = parse_list(&cmd); + imap->ns_shared = parse_list(&cmd); + } else if (!strcmp("OK", arg) || !strcmp("BAD", arg) || + !strcmp("NO", arg) || !strcmp("BYE", arg)) { + if ((resp = parse_response_code(ctx, NULL, cmd)) != RESP_OK) return resp; - } else if (!strcmp( "CAPABILITY", arg )) - parse_capability( imap, cmd ); - else if ((arg1 = next_arg( &cmd ))) { - if (!strcmp( "EXISTS", arg1 )) - ctx->gen.count = atoi( arg ); - else if (!strcmp( "RECENT", arg1 )) - ctx->gen.recent = atoi( arg ); + } else if (!strcmp("CAPABILITY", arg)) + parse_capability(imap, cmd); + else if ((arg1 = next_arg(&cmd))) { + if (!strcmp("EXISTS", arg1)) + ctx->gen.count = atoi(arg); + else if (!strcmp("RECENT", arg1)) + ctx->gen.recent = atoi(arg); } else { - fprintf( stderr, "IMAP error: unable to parse untagged response\n" ); + fprintf(stderr, "IMAP error: unable to parse untagged response\n"); return RESP_BAD; } } else if (!imap->in_progress) { - fprintf( stderr, "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" ); + fprintf(stderr, "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : ""); return RESP_BAD; } else if (*arg == '+') { /* This can happen only with the last command underway, as @@ -788,57 +874,57 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) cmdp = (struct imap_cmd *)((char *)imap->in_progress_append - offsetof(struct imap_cmd, next)); if (cmdp->cb.data) { - n = socket_write( &imap->buf.sock, cmdp->cb.data, cmdp->cb.dlen ); - free( cmdp->cb.data ); + n = socket_write(&imap->buf.sock, cmdp->cb.data, cmdp->cb.dlen); + free(cmdp->cb.data); cmdp->cb.data = NULL; if (n != (int)cmdp->cb.dlen) return RESP_BAD; } else if (cmdp->cb.cont) { - if (cmdp->cb.cont( ctx, cmdp, cmd )) + if (cmdp->cb.cont(ctx, cmdp, cmd)) return RESP_BAD; } else { - fprintf( stderr, "IMAP error: unexpected command continuation request\n" ); + fprintf(stderr, "IMAP error: unexpected command continuation request\n"); return RESP_BAD; } - if (socket_write( &imap->buf.sock, "\r\n", 2 ) != 2) + if (socket_write(&imap->buf.sock, "\r\n", 2) != 2) return RESP_BAD; if (!cmdp->cb.cont) imap->literal_pending = 0; if (!tcmd) return DRV_OK; } else { - tag = atoi( arg ); + tag = atoi(arg); for (pcmdp = &imap->in_progress; (cmdp = *pcmdp); pcmdp = &cmdp->next) if (cmdp->tag == tag) goto gottag; - fprintf( stderr, "IMAP error: unexpected tag %s\n", arg ); + fprintf(stderr, "IMAP error: unexpected tag %s\n", arg); return RESP_BAD; - gottag: + gottag: if (!(*pcmdp = cmdp->next)) imap->in_progress_append = pcmdp; imap->num_in_progress--; if (cmdp->cb.cont || cmdp->cb.data) imap->literal_pending = 0; - arg = next_arg( &cmd ); - if (!strcmp( "OK", arg )) + arg = next_arg(&cmd); + if (!strcmp("OK", arg)) resp = DRV_OK; else { - if (!strcmp( "NO", arg )) { - if (cmdp->cb.create && cmd && (cmdp->cb.trycreate || !memcmp( cmd, "[TRYCREATE]", 11 ))) { /* SELECT, APPEND or UID COPY */ - p = strchr( cmdp->cmd, '"' ); - if (!issue_imap_cmd( ctx, NULL, "CREATE \"%.*s\"", strchr( p + 1, '"' ) - p + 1, p )) { + if (!strcmp("NO", arg)) { + if (cmdp->cb.create && cmd && (cmdp->cb.trycreate || !memcmp(cmd, "[TRYCREATE]", 11))) { /* SELECT, APPEND or UID COPY */ + p = strchr(cmdp->cmd, '"'); + if (!issue_imap_cmd(ctx, NULL, "CREATE \"%.*s\"", strchr(p + 1, '"') - p + 1, p)) { resp = RESP_BAD; goto normal; } /* not waiting here violates the spec, but a server that does not grok this nonetheless violates it too. */ cmdp->cb.create = 0; - if (!(ncmdp = issue_imap_cmd( ctx, &cmdp->cb, "%s", cmdp->cmd ))) { + if (!(ncmdp = issue_imap_cmd(ctx, &cmdp->cb, "%s", cmdp->cmd))) { resp = RESP_BAD; goto normal; } - free( cmdp->cmd ); - free( cmdp ); + free(cmdp->cmd); + free(cmdp); if (!tcmd) return 0; /* ignored */ if (cmdp == tcmd) @@ -846,21 +932,21 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) continue; } resp = RESP_NO; - } else /*if (!strcmp( "BAD", arg ))*/ + } else /*if (!strcmp("BAD", arg))*/ resp = RESP_BAD; - fprintf( stderr, "IMAP command '%s' returned response (%s) - %s\n", - memcmp (cmdp->cmd, "LOGIN", 5) ? + fprintf(stderr, "IMAP command '%s' returned response (%s) - %s\n", + memcmp(cmdp->cmd, "LOGIN", 5) ? cmdp->cmd : "LOGIN <user> <pass>", arg, cmd ? cmd : ""); } - if ((resp2 = parse_response_code( ctx, &cmdp->cb, cmd )) > resp) + if ((resp2 = parse_response_code(ctx, &cmdp->cb, cmd)) > resp) resp = resp2; - normal: + normal: if (cmdp->cb.done) - cmdp->cb.done( ctx, cmdp, resp ); - free( cmdp->cb.data ); - free( cmdp->cmd ); - free( cmdp ); + cmdp->cb.done(ctx, cmdp, resp); + free(cmdp->cb.data); + free(cmdp->cmd); + free(cmdp); if (!tcmd || tcmd == cmdp) return resp; } @@ -868,170 +954,184 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) /* not reached */ } -static void -imap_close_server( imap_store_t *ictx ) +static void imap_close_server(struct imap_store *ictx) { - imap_t *imap = ictx->imap; + struct imap *imap = ictx->imap; if (imap->buf.sock.fd != -1) { - imap_exec( ictx, NULL, "LOGOUT" ); - close( imap->buf.sock.fd ); + imap_exec(ictx, NULL, "LOGOUT"); + socket_shutdown(&imap->buf.sock); } - free_list( imap->ns_personal ); - free_list( imap->ns_other ); - free_list( imap->ns_shared ); - free( imap ); + free_list(imap->ns_personal); + free_list(imap->ns_other); + free_list(imap->ns_shared); + free(imap); } -static void -imap_close_store( store_t *ctx ) +static void imap_close_store(struct store *ctx) { - imap_close_server( (imap_store_t *)ctx ); - free_generic_messages( ctx->msgs ); - free( ctx ); + imap_close_server((struct imap_store *)ctx); + free_generic_messages(ctx->msgs); + free(ctx); } -static store_t * -imap_open_store( imap_server_conf_t *srvc ) +static struct store *imap_open_store(struct imap_server_conf *srvc) { - imap_store_t *ctx; - imap_t *imap; + struct imap_store *ctx; + struct imap *imap; char *arg, *rsp; struct hostent *he; struct sockaddr_in addr; int s, a[2], preauth; pid_t pid; - ctx = xcalloc( sizeof(*ctx), 1 ); + ctx = xcalloc(sizeof(*ctx), 1); - ctx->imap = imap = xcalloc( sizeof(*imap), 1 ); + ctx->imap = imap = xcalloc(sizeof(*imap), 1); imap->buf.sock.fd = -1; imap->in_progress_append = &imap->in_progress; /* open connection to IMAP server */ if (srvc->tunnel) { - imap_info( "Starting tunnel '%s'... ", srvc->tunnel ); + imap_info("Starting tunnel '%s'... ", srvc->tunnel); - if (socketpair( PF_UNIX, SOCK_STREAM, 0, a )) { - perror( "socketpair" ); - exit( 1 ); + if (socketpair(PF_UNIX, SOCK_STREAM, 0, a)) { + perror("socketpair"); + exit(1); } pid = fork(); if (pid < 0) - _exit( 127 ); + _exit(127); if (!pid) { - if (dup2( a[0], 0 ) == -1 || dup2( a[0], 1 ) == -1) - _exit( 127 ); - close( a[0] ); - close( a[1] ); - execl( "/bin/sh", "sh", "-c", srvc->tunnel, NULL ); - _exit( 127 ); + if (dup2(a[0], 0) == -1 || dup2(a[0], 1) == -1) + _exit(127); + close(a[0]); + close(a[1]); + execl("/bin/sh", "sh", "-c", srvc->tunnel, NULL); + _exit(127); } - close (a[0]); + close(a[0]); imap->buf.sock.fd = a[1]; - imap_info( "ok\n" ); + imap_info("ok\n"); } else { - memset( &addr, 0, sizeof(addr) ); - addr.sin_port = htons( srvc->port ); + memset(&addr, 0, sizeof(addr)); + addr.sin_port = htons(srvc->port); addr.sin_family = AF_INET; - imap_info( "Resolving %s... ", srvc->host ); - he = gethostbyname( srvc->host ); + imap_info("Resolving %s... ", srvc->host); + he = gethostbyname(srvc->host); if (!he) { - perror( "gethostbyname" ); + perror("gethostbyname"); goto bail; } - imap_info( "ok\n" ); + imap_info("ok\n"); addr.sin_addr.s_addr = *((int *) he->h_addr_list[0]); - s = socket( PF_INET, SOCK_STREAM, 0 ); + s = socket(PF_INET, SOCK_STREAM, 0); - imap_info( "Connecting to %s:%hu... ", inet_ntoa( addr.sin_addr ), ntohs( addr.sin_port ) ); - if (connect( s, (struct sockaddr *)&addr, sizeof(addr) )) { - close( s ); - perror( "connect" ); + imap_info("Connecting to %s:%hu... ", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + if (connect(s, (struct sockaddr *)&addr, sizeof(addr))) { + close(s); + perror("connect"); goto bail; } - imap_info( "ok\n" ); imap->buf.sock.fd = s; + if (srvc->use_ssl && + ssl_socket_connect(&imap->buf.sock, 0, srvc->ssl_verify)) { + close(s); + goto bail; + } + imap_info("ok\n"); } /* read the greeting string */ - if (buffer_gets( &imap->buf, &rsp )) { - fprintf( stderr, "IMAP error: no greeting response\n" ); + if (buffer_gets(&imap->buf, &rsp)) { + fprintf(stderr, "IMAP error: no greeting response\n"); goto bail; } - arg = next_arg( &rsp ); - if (!arg || *arg != '*' || (arg = next_arg( &rsp )) == NULL) { - fprintf( stderr, "IMAP error: invalid greeting response\n" ); + arg = next_arg(&rsp); + if (!arg || *arg != '*' || (arg = next_arg(&rsp)) == NULL) { + fprintf(stderr, "IMAP error: invalid greeting response\n"); goto bail; } preauth = 0; - if (!strcmp( "PREAUTH", arg )) + if (!strcmp("PREAUTH", arg)) preauth = 1; - else if (strcmp( "OK", arg ) != 0) { - fprintf( stderr, "IMAP error: unknown greeting response\n" ); + else if (strcmp("OK", arg) != 0) { + fprintf(stderr, "IMAP error: unknown greeting response\n"); goto bail; } - parse_response_code( ctx, NULL, rsp ); - if (!imap->caps && imap_exec( ctx, NULL, "CAPABILITY" ) != RESP_OK) + parse_response_code(ctx, NULL, rsp); + if (!imap->caps && imap_exec(ctx, NULL, "CAPABILITY") != RESP_OK) goto bail; if (!preauth) { - - imap_info ("Logging in...\n"); +#ifndef NO_OPENSSL + if (!srvc->use_ssl && CAP(STARTTLS)) { + if (imap_exec(ctx, 0, "STARTTLS") != RESP_OK) + goto bail; + if (ssl_socket_connect(&imap->buf.sock, 1, + srvc->ssl_verify)) + goto bail; + /* capabilities may have changed, so get the new capabilities */ + if (imap_exec(ctx, 0, "CAPABILITY") != RESP_OK) + goto bail; + } +#endif + imap_info("Logging in...\n"); if (!srvc->user) { - fprintf( stderr, "Skipping server %s, no user\n", srvc->host ); + fprintf(stderr, "Skipping server %s, no user\n", srvc->host); goto bail; } if (!srvc->pass) { char prompt[80]; - sprintf( prompt, "Password (%s@%s): ", srvc->user, srvc->host ); - arg = getpass( prompt ); + sprintf(prompt, "Password (%s@%s): ", srvc->user, srvc->host); + arg = getpass(prompt); if (!arg) { - perror( "getpass" ); - exit( 1 ); + perror("getpass"); + exit(1); } if (!*arg) { - fprintf( stderr, "Skipping account %s@%s, no password\n", srvc->user, srvc->host ); + fprintf(stderr, "Skipping account %s@%s, no password\n", srvc->user, srvc->host); goto bail; } /* * getpass() returns a pointer to a static buffer. make a copy * for long term storage. */ - srvc->pass = xstrdup( arg ); + srvc->pass = xstrdup(arg); } if (CAP(NOLOGIN)) { - fprintf( stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host ); + fprintf(stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host); goto bail; } - imap_warn( "*** IMAP Warning *** Password is being sent in the clear\n" ); - if (imap_exec( ctx, NULL, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass ) != RESP_OK) { - fprintf( stderr, "IMAP error: LOGIN failed\n" ); + if (!imap->buf.sock.ssl) + imap_warn("*** IMAP Warning *** Password is being " + "sent in the clear\n"); + if (imap_exec(ctx, NULL, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass) != RESP_OK) { + fprintf(stderr, "IMAP error: LOGIN failed\n"); goto bail; } } /* !preauth */ ctx->prefix = ""; ctx->trashnc = 1; - return (store_t *)ctx; + return (struct store *)ctx; - bail: - imap_close_store( &ctx->gen ); +bail: + imap_close_store(&ctx->gen); return NULL; } -static int -imap_make_flags( int flags, char *buf ) +static int imap_make_flags(int flags, char *buf) { const char *s; unsigned i, d; @@ -1050,11 +1150,10 @@ imap_make_flags( int flags, char *buf ) #define TUIDL 8 -static int -imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) +static int imap_store_msg(struct store *gctx, struct msg_data *data, int *uid) { - imap_store_t *ctx = (imap_store_t *)gctx; - imap_t *imap = ctx->imap; + struct imap_store *ctx = (struct imap_store *)gctx; + struct imap *imap = ctx->imap; struct imap_cmd_cb cb; char *fmap, *buf; const char *prefix, *box; @@ -1062,14 +1161,14 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) int start, sbreak = 0, ebreak = 0; char flagstr[128], tuid[TUIDL * 2 + 1]; - memset( &cb, 0, sizeof(cb) ); + memset(&cb, 0, sizeof(cb)); fmap = data->data; len = data->len; nocr = !data->crlf; extra = 0, i = 0; if (!CAP(UIDPLUS) && uid) { - nloop: + nloop: start = i; while (i < len) if (fmap[i++] == '\n') { @@ -1078,18 +1177,18 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) sbreak = ebreak = i - 2 + nocr; goto mktid; } - if (!memcmp( fmap + start, "X-TUID: ", 8 )) { + if (!memcmp(fmap + start, "X-TUID: ", 8)) { extra -= (ebreak = i) - (sbreak = start) + nocr; goto mktid; } goto nloop; } /* invalid message */ - free( fmap ); + free(fmap); return DRV_MSG_BAD; - mktid: + mktid: for (j = 0; j < TUIDL; j++) - sprintf( tuid + j * 2, "%02x", arc4_getbyte() ); + sprintf(tuid + j * 2, "%02x", arc4_getbyte()); extra += 8 + TUIDL * 2 + 2; } if (nocr) @@ -1098,7 +1197,7 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) extra++; cb.dlen = len + extra; - buf = cb.data = xmalloc( cb.dlen ); + buf = cb.data = xmalloc(cb.dlen); i = 0; if (!CAP(UIDPLUS) && uid) { if (nocr) { @@ -1109,12 +1208,12 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) } else *buf++ = fmap[i]; } else { - memcpy( buf, fmap, sbreak ); + memcpy(buf, fmap, sbreak); buf += sbreak; } - memcpy( buf, "X-TUID: ", 8 ); + memcpy(buf, "X-TUID: ", 8); buf += 8; - memcpy( buf, tuid, TUIDL * 2 ); + memcpy(buf, tuid, TUIDL * 2); buf += TUIDL * 2; *buf++ = '\r'; *buf++ = '\n'; @@ -1128,13 +1227,13 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) } else *buf++ = fmap[i]; } else - memcpy( buf, fmap + i, len - i ); + memcpy(buf, fmap + i, len - i); - free( fmap ); + free(fmap); d = 0; if (data->flags) { - d = imap_make_flags( data->flags, flagstr ); + d = imap_make_flags(data->flags, flagstr); flagstr[d++] = ' '; } flagstr[d] = 0; @@ -1147,11 +1246,11 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) imap->caps = imap->rcaps & ~(1 << LITERALPLUS); } else { box = gctx->name; - prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix; + prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix; cb.create = 0; } cb.ctx = uid; - ret = imap_exec_m( ctx, &cb, "APPEND \"%s%s\" %s", prefix, box, flagstr ); + ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" %s", prefix, box, flagstr); imap->caps = imap->rcaps; if (ret != DRV_OK) return ret; @@ -1165,8 +1264,7 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) #define CHUNKSIZE 0x1000 -static int -read_message( FILE *f, msg_data_t *msg ) +static int read_message(FILE *f, struct msg_data *msg) { struct strbuf buf; @@ -1183,8 +1281,7 @@ read_message( FILE *f, msg_data_t *msg ) return msg->len; } -static int -count_messages( msg_data_t *msg ) +static int count_messages(struct msg_data *msg) { int count = 0; char *p = msg->data; @@ -1194,7 +1291,7 @@ count_messages( msg_data_t *msg ) count++; p += 5; } - p = strstr( p+5, "\nFrom "); + p = strstr(p+5, "\nFrom "); if (!p) break; p++; @@ -1202,22 +1299,21 @@ count_messages( msg_data_t *msg ) return count; } -static int -split_msg( msg_data_t *all_msgs, msg_data_t *msg, int *ofs ) +static int split_msg(struct msg_data *all_msgs, struct msg_data *msg, int *ofs) { char *p, *data; - memset( msg, 0, sizeof *msg ); + memset(msg, 0, sizeof *msg); if (*ofs >= all_msgs->len) return 0; - data = &all_msgs->data[ *ofs ]; + data = &all_msgs->data[*ofs]; msg->len = all_msgs->len - *ofs; if (msg->len < 5 || prefixcmp(data, "From ")) return 0; - p = strchr( data, '\n' ); + p = strchr(data, '\n'); if (p) { p = &p[1]; msg->len -= p-data; @@ -1225,7 +1321,7 @@ split_msg( msg_data_t *all_msgs, msg_data_t *msg, int *ofs ) data = p; } - p = strstr( data, "\nFrom " ); + p = strstr(data, "\nFrom "); if (p) msg->len = &p[1] - data; @@ -1234,24 +1330,24 @@ split_msg( msg_data_t *all_msgs, msg_data_t *msg, int *ofs ) return 1; } -static imap_server_conf_t server = -{ +static struct imap_server_conf server = { NULL, /* name */ NULL, /* tunnel */ NULL, /* host */ 0, /* port */ NULL, /* user */ NULL, /* pass */ + 0, /* use_ssl */ + 1, /* ssl_verify */ }; static char *imap_folder; -static int -git_imap_config(const char *key, const char *val, void *cb) +static int git_imap_config(const char *key, const char *val, void *cb) { char imap_key[] = "imap."; - if (strncmp( key, imap_key, sizeof imap_key - 1 )) + if (strncmp(key, imap_key, sizeof imap_key - 1)) return 0; if (!val) @@ -1259,90 +1355,96 @@ git_imap_config(const char *key, const char *val, void *cb) key += sizeof imap_key - 1; - if (!strcmp( "folder", key )) { - imap_folder = xstrdup( val ); - } else if (!strcmp( "host", key )) { - { - if (!prefixcmp(val, "imap:")) - val += 5; - if (!server.port) - server.port = 143; + if (!strcmp("folder", key)) { + imap_folder = xstrdup(val); + } else if (!strcmp("host", key)) { + if (!prefixcmp(val, "imap:")) + val += 5; + else if (!prefixcmp(val, "imaps:")) { + val += 6; + server.use_ssl = 1; } if (!prefixcmp(val, "//")) val += 2; - server.host = xstrdup( val ); - } - else if (!strcmp( "user", key )) - server.user = xstrdup( val ); - else if (!strcmp( "pass", key )) - server.pass = xstrdup( val ); - else if (!strcmp( "port", key )) - server.port = git_config_int( key, val ); - else if (!strcmp( "tunnel", key )) - server.tunnel = xstrdup( val ); + server.host = xstrdup(val); + } else if (!strcmp("user", key)) + server.user = xstrdup(val); + else if (!strcmp("pass", key)) + server.pass = xstrdup(val); + else if (!strcmp("port", key)) + server.port = git_config_int(key, val); + else if (!strcmp("tunnel", key)) + server.tunnel = xstrdup(val); + else if (!strcmp("sslverify", key)) + server.ssl_verify = git_config_bool(key, val); return 0; } -int -main(int argc, char **argv) +int main(int argc, char **argv) { - msg_data_t all_msgs, msg; - store_t *ctx = NULL; + struct msg_data all_msgs, msg; + struct store *ctx = NULL; int uid = 0; int ofs = 0; int r; int total, n = 0; + int nongit_ok; /* init the random number generator */ arc4_init(); + setup_git_directory_gently(&nongit_ok); git_config(git_imap_config, NULL); + if (!server.port) + server.port = server.use_ssl ? 993 : 143; + if (!imap_folder) { - fprintf( stderr, "no imap store specified\n" ); + fprintf(stderr, "no imap store specified\n"); return 1; } if (!server.host) { if (!server.tunnel) { - fprintf( stderr, "no imap host specified\n" ); + fprintf(stderr, "no imap host specified\n"); return 1; } server.host = "tunnel"; } /* read the messages */ - if (!read_message( stdin, &all_msgs )) { - fprintf(stderr,"nothing to send\n"); + if (!read_message(stdin, &all_msgs)) { + fprintf(stderr, "nothing to send\n"); return 1; } - total = count_messages( &all_msgs ); + total = count_messages(&all_msgs); if (!total) { - fprintf(stderr,"no messages to send\n"); + fprintf(stderr, "no messages to send\n"); return 1; } /* write it to the imap server */ - ctx = imap_open_store( &server ); + ctx = imap_open_store(&server); if (!ctx) { - fprintf( stderr,"failed to open store\n"); + fprintf(stderr, "failed to open store\n"); return 1; } - fprintf( stderr, "sending %d message%s\n", total, (total!=1)?"s":"" ); + fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : ""); ctx->name = imap_folder; while (1) { unsigned percent = n * 100 / total; - fprintf( stderr, "%4u%% (%d/%d) done\r", percent, n, total ); - if (!split_msg( &all_msgs, &msg, &ofs )) + fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total); + if (!split_msg(&all_msgs, &msg, &ofs)) + break; + r = imap_store_msg(ctx, &msg, &uid); + if (r != DRV_OK) break; - r = imap_store_msg( ctx, &msg, &uid ); - if (r != DRV_OK) break; n++; } - fprintf( stderr,"\n" ); + fprintf(stderr, "\n"); - imap_close_store( ctx ); + imap_close_store(ctx); return 0; } @@ -1,4 +1,5 @@ #include "cache.h" +#include "run-command.h" /* * This is split up from the rest of git so that we can do @@ -8,7 +9,7 @@ static int spawned_pager; #ifndef __MINGW32__ -static void run_pager(const char *pager) +static void pager_preexec(void) { /* * Work around bug in "less" by not starting it until we @@ -20,17 +21,13 @@ static void run_pager(const char *pager) FD_SET(0, &in); select(1, &in, NULL, &in, NULL); - execlp(pager, pager, NULL); - execl("/bin/sh", "sh", "-c", pager, NULL); + setenv("LESS", "FRSX", 0); } -#else -#include "run-command.h" +#endif static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; -static struct child_process pager_process = { - .argv = pager_argv, - .in = -1 -}; +static struct child_process pager_process; + static void wait_for_pager(void) { fflush(stdout); @@ -40,14 +37,9 @@ static void wait_for_pager(void) close(2); finish_command(&pager_process); } -#endif void setup_pager(void) { -#ifndef __MINGW32__ - pid_t pid; - int fd[2]; -#endif const char *pager = getenv("GIT_PAGER"); if (!isatty(1)) @@ -66,37 +58,13 @@ void setup_pager(void) spawned_pager = 1; /* means we are emitting to terminal */ -#ifndef __MINGW32__ - if (pipe(fd) < 0) - return; - pid = fork(); - if (pid < 0) { - close(fd[0]); - close(fd[1]); - return; - } - - /* return in the child */ - if (!pid) { - dup2(fd[1], 1); - dup2(fd[1], 2); - close(fd[0]); - close(fd[1]); - return; - } - - /* The original process turns into the PAGER */ - dup2(fd[0], 0); - close(fd[0]); - close(fd[1]); - - setenv("LESS", "FRSX", 0); - run_pager(pager); - die("unable to execute pager '%s'", pager); - exit(255); -#else /* spawn the pager */ pager_argv[2] = pager; + pager_process.argv = pager_argv; + pager_process.in = -1; +#ifndef __MINGW32__ + pager_process.preexec_cb = pager_preexec; +#endif if (start_command(&pager_process)) return; @@ -107,7 +75,6 @@ void setup_pager(void) /* this makes sure that the parent terminates after the pager */ atexit(wait_for_pager); -#endif } int pager_in_use(void) @@ -579,8 +579,7 @@ int valid_fetch_refspec(const char *fetch_refspec_str) struct refspec *refspec; refspec = parse_refspec_internal(1, fetch_refspec, 1, 1); - if (refspec) - free(refspec); + free(refspec); return !!refspec; } diff --git a/run-command.c b/run-command.c index bbb9c777e5..caab374577 100644 --- a/run-command.c +++ b/run-command.c @@ -111,6 +111,8 @@ int start_command(struct child_process *cmd) unsetenv(*cmd->env); } } + if (cmd->preexec_cb) + cmd->preexec_cb(); if (cmd->git_cmd) { execv_git_cmd(cmd->argv); } else { diff --git a/run-command.h b/run-command.h index 5203a9ebb1..4f2b7d7d40 100644 --- a/run-command.h +++ b/run-command.h @@ -42,6 +42,7 @@ struct child_process { unsigned no_stderr:1; unsigned git_cmd:1; /* if this is to be git sub-command */ unsigned stdout_to_stderr:1; + void (*preexec_cb)(void); }; int start_command(struct child_process *); diff --git a/sha1_file.c b/sha1_file.c index 32e4664b1b..2aff59b90f 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -2360,51 +2360,22 @@ int has_sha1_file(const unsigned char *sha1) return has_loose_object(sha1); } -int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object) +static int index_mem(unsigned char *sha1, void *buf, size_t size, + int write_object, enum object_type type, const char *path) { - struct strbuf buf; - int ret; - - strbuf_init(&buf, 0); - if (strbuf_read(&buf, fd, 4096) < 0) { - strbuf_release(&buf); - return -1; - } - - if (!type) - type = blob_type; - if (write_object) - ret = write_sha1_file(buf.buf, buf.len, type, sha1); - else - ret = hash_sha1_file(buf.buf, buf.len, type, sha1); - strbuf_release(&buf); - - return ret; -} - -int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, - enum object_type type, const char *path) -{ - size_t size = xsize_t(st->st_size); - void *buf = NULL; int ret, re_allocated = 0; - if (size) - buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - close(fd); - if (!type) type = OBJ_BLOB; /* * Convert blobs to git internal format */ - if ((type == OBJ_BLOB) && S_ISREG(st->st_mode)) { + if ((type == OBJ_BLOB) && path) { struct strbuf nbuf; strbuf_init(&nbuf, 0); if (convert_to_git(path, buf, size, &nbuf, write_object ? safe_crlf : 0)) { - munmap(buf, size); buf = strbuf_detach(&nbuf, &size); re_allocated = 1; } @@ -2414,12 +2385,33 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, ret = write_sha1_file(buf, size, typename(type), sha1); else ret = hash_sha1_file(buf, size, typename(type), sha1); - if (re_allocated) { + if (re_allocated) free(buf); - return ret; - } - if (size) + return ret; +} + +int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, + enum object_type type, const char *path) +{ + int ret; + size_t size = xsize_t(st->st_size); + + if (!S_ISREG(st->st_mode)) { + struct strbuf sbuf; + strbuf_init(&sbuf, 0); + if (strbuf_read(&sbuf, fd, 4096) >= 0) + ret = index_mem(sha1, sbuf.buf, sbuf.len, write_object, + type, path); + else + ret = -1; + strbuf_release(&sbuf); + } else if (size) { + void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + ret = index_mem(sha1, buf, size, write_object, type, path); munmap(buf, size); + } else + ret = index_mem(sha1, NULL, size, write_object, type, path); + close(fd); return ret; } diff --git a/t/.gitignore b/t/.gitignore index b27e280083..7dcbb232cd 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -1,2 +1,2 @@ -/trash directory +/trash directory* /test-results diff --git a/t/Makefile b/t/Makefile index 0d65cedaa6..ed49c20b16 100644 --- a/t/Makefile +++ b/t/Makefile @@ -14,7 +14,8 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) TSVN = $(wildcard t91[0-9][0-9]-*.sh) -all: pre-clean $(T) aggregate-results clean +all: pre-clean + $(MAKE) aggregate-results-and-cleanup $(T): @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) @@ -25,6 +26,10 @@ pre-clean: clean: $(RM) -r 'trash directory' test-results +aggregate-results-and-cleanup: $(T) + $(MAKE) aggregate-results + $(MAKE) clean + aggregate-results: '$(SHELL_PATH_SQ)' ./aggregate-results.sh test-results/t*-* @@ -34,4 +39,3 @@ full-svn-test: $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=0 LC_ALL=en_US.UTF-8 .PHONY: pre-clean $(T) aggregate-results clean -.NOTPARALLEL: diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index aa9dd580a6..5e40cec530 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -14,6 +14,8 @@ _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" compare_change () { sed >current \ + -e '1{/^diff --git /d;}' \ + -e '2{/^index /d;}' \ -e '/^--- /d; /^+++ /d; /^@@ /d;' \ -e 's/^\(.[0-7][0-7][0-7][0-7][0-7][0-7]\) '"$_x40"' /\1 X /' "$1" test_cmp expected current @@ -75,7 +77,7 @@ test_expect_success \ git update-index --add yomin && git read-tree -m -u $treeH $treeM && git ls-files --stage >4.out || return 1 - diff -U0 M.out 4.out >4diff.out + git diff -U0 --no-index M.out 4.out >4diff.out compare_change 4diff.out expected && check_cache_at yomin clean && sum bozbar frotz nitfol >actual4.sum && @@ -94,7 +96,7 @@ test_expect_success \ echo yomin yomin >yomin && git read-tree -m -u $treeH $treeM && git ls-files --stage >5.out || return 1 - diff -U0 M.out 5.out >5diff.out + git diff -U0 --no-index M.out 5.out >5diff.out compare_change 5diff.out expected && check_cache_at yomin dirty && sum bozbar frotz nitfol >actual5.sum && @@ -206,7 +208,7 @@ test_expect_success \ git update-index --add nitfol && git read-tree -m -u $treeH $treeM && git ls-files --stage >14.out || return 1 - diff -U0 M.out 14.out >14diff.out + git diff -U0 --no-index M.out 14.out >14diff.out compare_change 14diff.out expected && sum bozbar frotz >actual14.sum && grep -v nitfol M.sum > expected14.sum && @@ -227,7 +229,7 @@ test_expect_success \ echo nitfol nitfol nitfol >nitfol && git read-tree -m -u $treeH $treeM && git ls-files --stage >15.out || return 1 - diff -U0 M.out 15.out >15diff.out + git diff -U0 --no-index M.out 15.out >15diff.out compare_change 15diff.out expected && check_cache_at nitfol dirty && sum bozbar frotz >actual15.sum && diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index 1ec0535138..fcdd15a358 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -49,16 +49,28 @@ setup_repo # Argument checking test_expect_success "multiple '--stdin's are rejected" ' - test_must_fail git hash-object --stdin --stdin < example + echo example | test_must_fail git hash-object --stdin --stdin ' test_expect_success "Can't use --stdin and --stdin-paths together" ' - test_must_fail git hash-object --stdin --stdin-paths && - test_must_fail git hash-object --stdin-paths --stdin + echo example | test_must_fail git hash-object --stdin --stdin-paths && + echo example | test_must_fail git hash-object --stdin-paths --stdin ' test_expect_success "Can't pass filenames as arguments with --stdin-paths" ' - test_must_fail git hash-object --stdin-paths hello < example + echo example | test_must_fail git hash-object --stdin-paths hello +' + +test_expect_success "Can't use --path with --stdin-paths" ' + echo example | test_must_fail git hash-object --stdin-paths --path=foo +' + +test_expect_success "Can't use --stdin-paths with --no-filters" ' + echo example | test_must_fail git hash-object --stdin-paths --no-filters +' + +test_expect_success "Can't use --path with --no-filters" ' + test_must_fail git hash-object --no-filters --path=foo ' # Behavior @@ -93,6 +105,42 @@ test_expect_success 'git hash-object --stdin file1 <file0 first operates on file test "$obname1" = "$obname1new" ' +test_expect_success 'check that appropriate filter is invoke when --path is used' ' + echo fooQ | tr Q "\\015" >file0 && + cp file0 file1 && + echo "file0 -crlf" >.gitattributes && + echo "file1 crlf" >>.gitattributes && + git config core.autocrlf true && + file0_sha=$(git hash-object file0) && + file1_sha=$(git hash-object file1) && + test "$file0_sha" != "$file1_sha" && + path1_sha=$(git hash-object --path=file1 file0) && + path0_sha=$(git hash-object --path=file0 file1) && + test "$file0_sha" = "$path0_sha" && + test "$file1_sha" = "$path1_sha" && + path1_sha=$(cat file0 | git hash-object --path=file1 --stdin) && + path0_sha=$(cat file1 | git hash-object --path=file0 --stdin) && + test "$file0_sha" = "$path0_sha" && + test "$file1_sha" = "$path1_sha" && + git config --unset core.autocrlf +' + +test_expect_success 'check that --no-filters option works' ' + echo fooQ | tr Q "\\015" >file0 && + cp file0 file1 && + echo "file0 -crlf" >.gitattributes && + echo "file1 crlf" >>.gitattributes && + git config core.autocrlf true && + file0_sha=$(git hash-object file0) && + file1_sha=$(git hash-object file1) && + test "$file0_sha" != "$file1_sha" && + nofilters_file1=$(git hash-object --no-filters file1) && + test "$file0_sha" = "$nofilters_file1" && + nofilters_file1=$(cat file1 | git hash-object --stdin) && + test "$file0_sha" = "$nofilters_file1" && + git config --unset core.autocrlf +' + pop_repo for args in "-w --stdin" "--stdin -w"; do diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 6110566aaa..f9eb67d835 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -341,4 +341,15 @@ test_expect_success 'checkdiff detects trailing blank lines' ' git diff --check | grep "ends with blank" ' +test_expect_success 'checkdiff allows new blank lines' ' + git checkout x && + mv x y && + ( + echo "/* This is new */" && + echo "" && + cat y + ) >x && + git diff --check +' + test_done diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh new file mode 100755 index 0000000000..4ca65e0332 --- /dev/null +++ b/t/t4029-diff-trailing-space.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# +# Copyright (c) Jim Meyering +# +test_description='diff honors config option, diff.suppress-blank-empty' + +. ./test-lib.sh + +cat <<\EOF > exp || +diff --git a/f b/f +index 5f6a263..8cb8bae 100644 +--- a/f ++++ b/f +@@ -1,2 +1,2 @@ + +-x ++y +EOF +exit 1 + +test_expect_success \ + "$test_description" \ + 'printf "\nx\n" > f && + git add f && + git commit -q -m. f && + printf "\ny\n" > f && + git config --bool diff.suppress-blank-empty true && + git diff f > actual && + test_cmp exp actual && + perl -i.bak -p -e "s/^\$/ /" exp && + git config --bool diff.suppress-blank-empty false && + git diff f > actual && + test_cmp exp actual && + git config --bool --unset diff.suppress-blank-empty && + git diff f > actual && + test_cmp exp actual + ' + +test_done diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index 3b6c3a9d97..fe14589427 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -44,4 +44,15 @@ test_expect_success 'Preserve NULs out of MIME encoded message' ' ' +test_expect_success 'mailinfo on from header without name works' ' + + mkdir info-from && + git mailsplit -oinfo-from "$TEST_DIRECTORY"/t5100/info-from.in && + test_cmp "$TEST_DIRECTORY"/t5100/info-from.in info-from/0001 && + git mailinfo info-from/msg info-from/patch \ + <info-from/0001 >info-from/out && + test_cmp "$TEST_DIRECTORY"/t5100/info-from.expect info-from/out + +' + test_done diff --git a/t/t5100/info-from.expect b/t/t5100/info-from.expect new file mode 100644 index 0000000000..c31d2eb550 --- /dev/null +++ b/t/t5100/info-from.expect @@ -0,0 +1,5 @@ +Author: bare@example.com +Email: bare@example.com +Subject: testing bare address in from header +Date: Sun, 25 May 2008 00:38:18 -0700 + diff --git a/t/t5100/info-from.in b/t/t5100/info-from.in new file mode 100644 index 0000000000..4f082093fc --- /dev/null +++ b/t/t5100/info-from.in @@ -0,0 +1,8 @@ +From 667d8940e719cddee1cfe237cbbe215e20270b09 Mon Sep 17 00:00:00 2001 +From: bare@example.com +Date: Sun, 25 May 2008 00:38:18 -0700 +Subject: [PATCH] testing bare address in from header + +commit message +--- +patch diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox index d7ca79b1fc..4bf7947b41 100644 --- a/t/t5100/sample.mbox +++ b/t/t5100/sample.mbox @@ -500,3 +500,4 @@ index 3e5fe51..aabfe5c 100644 1.6.0.rc2 --=-=-=-- + diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index a3c8941c72..8ced59321e 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -262,4 +262,14 @@ for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do " done +test_expect_success 'an unusual tag with an incomplete line' ' + + git tag -m "bogo" bogo && + bogo=$(git cat-file tag bogo) && + bogo=$(printf "%s" "$bogo" | git mktag) && + git tag -f bogo "$bogo" && + git for-each-ref --format "%(body)" refs/tags/bogo + +' + test_done diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 9ad5d635a2..943dd57aac 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -337,4 +337,15 @@ test_expect_success \ test refs/heads/delete-me = "$(git symbolic-ref HEAD)" && test_must_fail git checkout --track -b track' +test_expect_success \ + 'checkout with --track fakes a sensible -b <name>' ' + git update-ref refs/remotes/origin/koala/bear renamer && + git checkout --track origin/koala/bear && + test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && + test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"' + +test_expect_success \ + 'checkout with --track, but without -b, fails with too short tracked name' ' + test_must_fail git checkout --track renamer' + test_done diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index 5eeb6c2b27..fee8fb77d4 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -488,4 +488,14 @@ test_expect_success 'merge c1 with c1 and c2' ' test_debug 'gitk --all' +test_expect_success 'merge fast-forward in a dirty tree' ' + git reset --hard c0 && + mv file file1 && + cat file1 >file && + rm -f file1 && + git merge c2 +' + +test_debug 'gitk --all' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 70ea7e089e..6212c46cc1 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -449,6 +449,11 @@ test_done () { # we will leave things as they are. say_color pass "passed all $msg" + + test -d "$remove_trash" && + cd "$(dirname "$remove_trash")" && + rm -rf "$(basename "$remove_trash")" + exit 0 ;; *) @@ -485,7 +490,8 @@ fi . ../GIT-BUILD-OPTIONS # Test repository -test="trash directory" +test="trash directory.$(basename "$0" .sh)" +remove_trash="$TEST_DIRECTORY/$test" rm -fr "$test" || { trap - exit echo >&5 "FATAL: Cannot prepare test area" diff --git a/templates/Makefile b/templates/Makefile index 9f3f1fc352..cc3fc3094c 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -48,4 +48,4 @@ clean: install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(template_instdir_SQ)' (cd blt && $(TAR) cf - .) | \ - (cd '$(DESTDIR_SQ)$(template_instdir_SQ)' && umask 022 && $(TAR) xf -) + (cd '$(DESTDIR_SQ)$(template_instdir_SQ)' && umask 022 && $(TAR) xfo -) diff --git a/xdiff-interface.c b/xdiff-interface.c index 61dc5c5470..944ad9887f 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -1,5 +1,12 @@ #include "cache.h" #include "xdiff-interface.h" +#include "strbuf.h" + +struct xdiff_emit_state { + xdiff_emit_consume_fn consume; + void *consume_callback_data; + struct strbuf remainder; +}; static int parse_num(char **cp_p, int *num_p) { @@ -55,13 +62,13 @@ static void consume_one(void *priv_, char *s, unsigned long size) unsigned long this_size; ep = memchr(s, '\n', size); this_size = (ep == NULL) ? size : (ep - s + 1); - priv->consume(priv, s, this_size); + priv->consume(priv->consume_callback_data, s, this_size); size -= this_size; s += this_size; } } -int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf) +static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf) { struct xdiff_emit_state *priv = priv_; int i; @@ -69,36 +76,22 @@ int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf) for (i = 0; i < nbuf; i++) { if (mb[i].ptr[mb[i].size-1] != '\n') { /* Incomplete line */ - priv->remainder = xrealloc(priv->remainder, - priv->remainder_size + - mb[i].size); - memcpy(priv->remainder + priv->remainder_size, - mb[i].ptr, mb[i].size); - priv->remainder_size += mb[i].size; + strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size); continue; } /* we have a complete line */ - if (!priv->remainder) { + if (!priv->remainder.len) { consume_one(priv, mb[i].ptr, mb[i].size); continue; } - priv->remainder = xrealloc(priv->remainder, - priv->remainder_size + - mb[i].size); - memcpy(priv->remainder + priv->remainder_size, - mb[i].ptr, mb[i].size); - consume_one(priv, priv->remainder, - priv->remainder_size + mb[i].size); - free(priv->remainder); - priv->remainder = NULL; - priv->remainder_size = 0; + strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size); + consume_one(priv, priv->remainder.buf, priv->remainder.len); + strbuf_reset(&priv->remainder); } - if (priv->remainder) { - consume_one(priv, priv->remainder, priv->remainder_size); - free(priv->remainder); - priv->remainder = NULL; - priv->remainder_size = 0; + if (priv->remainder.len) { + consume_one(priv, priv->remainder.buf, priv->remainder.len); + strbuf_reset(&priv->remainder); } return 0; } @@ -141,6 +134,25 @@ int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t co return xdl_diff(&a, &b, xpp, xecfg, xecb); } +int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2, + xdiff_emit_consume_fn fn, void *consume_callback_data, + xpparam_t const *xpp, + xdemitconf_t const *xecfg, xdemitcb_t *xecb) +{ + int ret; + struct xdiff_emit_state state; + + memset(&state, 0, sizeof(state)); + state.consume = fn; + state.consume_callback_data = consume_callback_data; + xecb->outf = xdiff_outf; + xecb->priv = &state; + strbuf_init(&state.remainder, 0); + ret = xdi_diff(mf1, mf2, xpp, xecfg, xecb); + strbuf_release(&state.remainder); + return ret; +} + int read_mmfile(mmfile_t *ptr, const char *filename) { struct stat st; diff --git a/xdiff-interface.h b/xdiff-interface.h index f7f791d96b..558492ba38 100644 --- a/xdiff-interface.h +++ b/xdiff-interface.h @@ -3,18 +3,13 @@ #include "xdiff/xdiff.h" -struct xdiff_emit_state; - typedef void (*xdiff_emit_consume_fn)(void *, char *, unsigned long); -struct xdiff_emit_state { - xdiff_emit_consume_fn consume; - char *remainder; - unsigned long remainder_size; -}; - int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb); -int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf); +int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2, + xdiff_emit_consume_fn fn, void *consume_callback_data, + xpparam_t const *xpp, + xdemitconf_t const *xecfg, xdemitcb_t *xecb); int parse_hunk_header(char *line, int len, int *ob, int *on, int *nb, int *nn); |