Merge branch 'wc/diff'
authorJunio C Hamano <gitster@pobox.com>
Sat, 15 Dec 2007 05:42:53 +0000 (21:42 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sat, 15 Dec 2007 05:42:53 +0000 (21:42 -0800)
* wc/diff:
Test interaction between diff --check and --exit-code
Use shorter error messages for whitespace problems
Add tests for "git diff --check" with core.whitespace options
Make "diff --check" output match "git apply"
Unify whitespace checking
diff --check: minor fixups
"diff --check" should affect exit status

15 files changed:
Documentation/technical/pack-format.txt
builtin-commit.c
config.c
fast-import.c
git-cvsexportcommit.perl
git-svn.perl
http-push.c
http-walker.c
http.c
http.h
remote.c
t/t7501-commit.sh
t/t9103-git-svn-tracked-directory-removed.sh [new file with mode: 0755]
transport.c
xdiff-interface.c
index e5b31c81fa3b5268c6d1bc0afcaec967f401ac28..a80baa4382ce72cd6d3e1f1719a17264fc36ee02 100644 (file)
@@ -1,9 +1,9 @@
 GIT pack format
 ===============
 
-= pack-*.pack file has the following format:
+= pack-*.pack files have the following format:
 
-   - The header appears at the beginning and consists of the following:
+   - A header appears at the beginning and consists of the following:
 
      4-byte signature:
          The signature is: {'P', 'A', 'C', 'K'}
@@ -34,18 +34,14 @@ GIT pack format
 
   - The trailer records 20-byte SHA1 checksum of all of the above.
 
-= pack-*.idx file has the following format:
+= Original (version 1) pack-*.idx files have the following format:
 
   - The header consists of 256 4-byte network byte order
     integers.  N-th entry of this table records the number of
     objects in the corresponding pack, the first byte of whose
-    object name are smaller than N.  This is called the
+    object name is less than or equal to N.  This is called the
     'first-level fan-out' table.
 
-    Observation: we would need to extend this to an array of
-    8-byte integers to go beyond 4G objects per pack, but it is
-    not strictly necessary.
-
   - The header is followed by sorted 24-byte entries, one entry
     per object in the pack.  Each entry is:
 
@@ -55,10 +51,6 @@ GIT pack format
 
     20-byte object name.
 
-    Observation: we would definitely need to extend this to
-    8-byte integer plus 20-byte object name to handle a packfile
-    that is larger than 4GB.
-
   - The file is concluded with a trailer:
 
     A copy of the 20-byte SHA1 checksum at the end of
@@ -68,31 +60,30 @@ GIT pack format
 
 Pack Idx file:
 
-       idx
-           +--------------------------------+
-           | fanout[0] = 2                  |-.
-           +--------------------------------+ |
+       --  +--------------------------------+
+fanout     | fanout[0] = 2 (for example)    |-.
+table      +--------------------------------+ |
            | fanout[1]                      | |
            +--------------------------------+ |
            | fanout[2]                      | |
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
-           | fanout[255]                    | |
-           +--------------------------------+ |
-main       | offset                         | |
-index      | object name 00XXXXXXXXXXXXXXXX | |
-table      +--------------------------------+ |
-           | offset                         | |
-           | object name 00XXXXXXXXXXXXXXXX | |
-           +--------------------------------+ |
-         .-| offset                         |<+
-         | | object name 01XXXXXXXXXXXXXXXX |
-         | +--------------------------------+
-         | | offset                         |
-         | | object name 01XXXXXXXXXXXXXXXX |
-         | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-         | | offset                         |
-         | | object name FFXXXXXXXXXXXXXXXX |
-         | +--------------------------------+
+           | fanout[255] = total objects    |---.
+       --  +--------------------------------+ | |
+main       | offset                         | | |
+index      | object name 00XXXXXXXXXXXXXXXX | | |
+table      +--------------------------------+ | |
+           | offset                         | | |
+           | object name 00XXXXXXXXXXXXXXXX | | |
+           +--------------------------------+<+ |
+         .-| offset                         |   |
+         | | object name 01XXXXXXXXXXXXXXXX |   |
+         | +--------------------------------+   |
+         | | offset                         |   |
+         | | object name 01XXXXXXXXXXXXXXXX |   |
+         | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   |
+         | | offset                         |   |
+         | | object name FFXXXXXXXXXXXXXXXX |   |
+       --| +--------------------------------+<--+
 trailer          | | packfile checksum              |
          | +--------------------------------+
          | | idxfile checksum               |
@@ -116,3 +107,40 @@ Pack file entry: <+
          20-byte base object name SHA1 (the size above is the
                size of the delta data that follows).
           delta data, deflated.
+
+
+= Version 2 pack-*.idx files support packs larger than 4 GiB, and
+  have some other reorganizations.  They have the format:
+
+  - A 4-byte magic number '\377tOc' which is an unreasonable
+    fanout[0] value.
+
+  - A 4-byte version number (= 2)
+
+  - A 256-entry fan-out table just like v1.
+
+  - A table of sorted 20-byte SHA1 object names.  These are
+    packed together without offset values to reduce the cache
+    footprint of the binary search for a specific object name.
+
+  - A table of 4-byte CRC32 values of the packed object data.
+    This is new in v2 so compressed data can be copied directly
+    from pack to pack during repacking withough undetected
+    data corruption.
+
+  - A table of 4-byte offset values (in network byte order).
+    These are usually 31-bit pack file offsets, but large
+    offsets are encoded as an index into the next table with
+    the msbit set.
+
+  - A table of 8-byte offset entries (empty for pack files less
+    than 2 GiB).  Pack files are organized with heavily used
+    objects toward the front, so most object references should
+    not need to refer to this table.
+
+  - The same trailer as a v1 pack file:
+
+    A copy of the 20-byte SHA1 checksum at the end of
+    corresponding packfile.
+
+    20-byte SHA1-checksum of all of the above.
index ad9f9211b39af6cc7d1f319b6a8da7c514a33f12..518ebe0347e631c72f4e2a83b948259ee20fd213 100644 (file)
@@ -537,7 +537,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
                die("Option -m cannot be combined with -c/-C/-F.");
        if (edit_message)
                use_message = edit_message;
-       if (amend)
+       if (amend && !use_message)
                use_message = "HEAD";
        if (use_message) {
                unsigned char sha1[20];
index 49d2b427e52008e612b534f0c567e9fadaeab6e3..9a5c5470cc5ac893399bcf2126e4d5ba601718ef 100644 (file)
--- a/config.c
+++ b/config.c
@@ -610,46 +610,36 @@ static int write_error(void)
 
 static int store_write_section(int fd, const char* key)
 {
-       const char *dot = strchr(key, '.');
-       int len1 = store.baselen, len2 = -1;
+       const char *dot;
+       int i, success;
+       struct strbuf sb;
 
-       dot = strchr(key, '.');
+       strbuf_init(&sb, 0);
+       dot = memchr(key, '.', store.baselen);
        if (dot) {
-               int dotlen = dot - key;
-               if (dotlen < len1) {
-                       len2 = len1 - dotlen - 1;
-                       len1 = dotlen;
+               strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
+               for (i = dot - key + 1; i < store.baselen; i++) {
+                       if (key[i] == '"')
+                               strbuf_addch(&sb, '\\');
+                       strbuf_addch(&sb, key[i]);
                }
+               strbuf_addstr(&sb, "\"]\n");
+       } else {
+               strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
        }
 
-       if (write_in_full(fd, "[", 1) != 1 ||
-           write_in_full(fd, key, len1) != len1)
-               return 0;
-       if (len2 >= 0) {
-               if (write_in_full(fd, " \"", 2) != 2)
-                       return 0;
-               while (--len2 >= 0) {
-                       unsigned char c = *++dot;
-                       if (c == '"')
-                               if (write_in_full(fd, "\\", 1) != 1)
-                                       return 0;
-                       if (write_in_full(fd, &c, 1) != 1)
-                               return 0;
-               }
-               if (write_in_full(fd, "\"", 1) != 1)
-                       return 0;
-       }
-       if (write_in_full(fd, "]\n", 2) != 2)
-               return 0;
+       success = write_in_full(fd, sb.buf, sb.len) == sb.len;
+       strbuf_release(&sb);
 
-       return 1;
+       return success;
 }
 
 static int store_write_pair(int fd, const char* key, const char* value)
 {
-       int i;
-       int length = strlen(key+store.baselen+1);
-       int quote = 0;
+       int i, success;
+       int length = strlen(key + store.baselen + 1);
+       const char *quote = "";
+       struct strbuf sb;
 
        /*
         * Check to see if the value needs to be surrounded with a dq pair.
@@ -659,43 +649,38 @@ static int store_write_pair(int fd, const char* key, const char* value)
         * configuration parser.
         */
        if (value[0] == ' ')
-               quote = 1;
+               quote = "\"";
        for (i = 0; value[i]; i++)
                if (value[i] == ';' || value[i] == '#')
-                       quote = 1;
-       if (i && value[i-1] == ' ')
-               quote = 1;
+                       quote = "\"";
+       if (i && value[i - 1] == ' ')
+               quote = "\"";
+
+       strbuf_init(&sb, 0);
+       strbuf_addf(&sb, "\t%.*s = %s",
+                   length, key + store.baselen + 1, quote);
 
-       if (write_in_full(fd, "\t", 1) != 1 ||
-           write_in_full(fd, key+store.baselen+1, length) != length ||
-           write_in_full(fd, " = ", 3) != 3)
-               return 0;
-       if (quote && write_in_full(fd, "\"", 1) != 1)
-               return 0;
        for (i = 0; value[i]; i++)
                switch (value[i]) {
                case '\n':
-                       if (write_in_full(fd, "\\n", 2) != 2)
-                               return 0;
+                       strbuf_addstr(&sb, "\\n");
                        break;
                case '\t':
-                       if (write_in_full(fd, "\\t", 2) != 2)
-                               return 0;
+                       strbuf_addstr(&sb, "\\t");
                        break;
                case '"':
                case '\\':
-                       if (write_in_full(fd, "\\", 1) != 1)
-                               return 0;
+                       strbuf_addch(&sb, '\\');
                default:
-                       if (write_in_full(fd, value+i, 1) != 1)
-                               return 0;
+                       strbuf_addch(&sb, value[i]);
                        break;
                }
-       if (quote && write_in_full(fd, "\"", 1) != 1)
-               return 0;
-       if (write_in_full(fd, "\n", 1) != 1)
-               return 0;
-       return 1;
+       strbuf_addf(&sb, "%s\n", quote);
+
+       success = write_in_full(fd, sb.buf, sb.len) == sb.len;
+       strbuf_release(&sb);
+
+       return success;
 }
 
 static ssize_t find_beginning_of_line(const char* contents, size_t size,
index 98c2bd535957a45e5ef189875859d4788d937e7e..4646c056f32818549635b6ecc6b1088dc08ff469 100644 (file)
@@ -196,7 +196,7 @@ struct mem_pool
        struct mem_pool *next_pool;
        char *next_free;
        char *end;
-       char space[FLEX_ARRAY]; /* more */
+       uintmax_t space[FLEX_ARRAY]; /* more */
 };
 
 struct atom_str
@@ -534,15 +534,15 @@ static void *pool_alloc(size_t len)
                total_allocd += sizeof(struct mem_pool) + mem_pool_alloc;
                p = xmalloc(sizeof(struct mem_pool) + mem_pool_alloc);
                p->next_pool = mem_pool;
-               p->next_free = p->space;
+               p->next_free = (char *) p->space;
                p->end = p->next_free + mem_pool_alloc;
                mem_pool = p;
        }
 
        r = p->next_free;
-       /* round out to a pointer alignment */
-       if (len & (sizeof(void*) - 1))
-               len += sizeof(void*) - (len & (sizeof(void*) - 1));
+       /* round out to a 'uintmax_t' alignment */
+       if (len & (sizeof(uintmax_t) - 1))
+               len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));
        p->next_free += len;
        return r;
 }
index 92e41620fd2a998e765a47c2c2ca7085834b14cc..d2e50c34292bc0ccb6e914ed595da9fd8a7e141d 100755 (executable)
 my %cvsstat;
 if (@canstatusfiles) {
     if ($opt_u) {
-      my @updated = safe_pipe_capture(@cvs, 'update', @canstatusfiles);
+      my @updated = xargs_safe_pipe_capture([@cvs, 'update'], @canstatusfiles);
       print @updated;
     }
     my @cvsoutput;
-    @cvsoutput= safe_pipe_capture(@cvs, 'status', @canstatusfiles);
+    @cvsoutput = xargs_safe_pipe_capture([@cvs, 'status'], @canstatusfiles);
     my $matchcount = 0;
     foreach my $l (@cvsoutput) {
         chomp $l;
 
 if ($opt_c) {
     print "Autocommit\n  $cmd\n";
-    print safe_pipe_capture(@cvs, 'commit', '-F', '.msg', @files);
+    print xargs_safe_pipe_capture([@cvs, 'commit', '-F', '.msg'], @files);
     if ($?) {
        die "Exiting: The commit did not succeed";
     }
@@ -335,15 +335,24 @@ sub safe_pipe_capture {
     return wantarray ? @output : join('',@output);
 }
 
-sub safe_pipe_capture_blob {
-    my $output;
-    if (my $pid = open my $child, '-|') {
-        local $/;
-       undef $/;
-       $output = (<$child>);
-       close $child or die join(' ',@_).": $! $?";
-    } else {
-       exec(@_) or die "$! $?"; # exec() can fail the executable can't be found
-    }
-    return $output;
+sub xargs_safe_pipe_capture {
+       my $MAX_ARG_LENGTH = 65536;
+       my $cmd = shift;
+       my @output;
+       my $output;
+       while(@_) {
+               my @args;
+               my $length = 0;
+               while(@_ && $length < $MAX_ARG_LENGTH) {
+                       push @args, shift;
+                       $length += length($args[$#args]);
+               }
+               if (wantarray) {
+                       push @output, safe_pipe_capture(@$cmd, @args);
+               }
+               else {
+                       $output .= safe_pipe_capture(@$cmd, @args);
+               }
+       }
+       return wantarray ? @output : $output;
 }
index 3aa7f8cb408402305df316d2ff90b69a3267c5a0..d411a343170cf8dce9d968b84f123855b03e53d3 100755 (executable)
@@ -3045,6 +3045,20 @@ sub add_file {
 
 sub add_directory {
        my ($self, $path, $cp_path, $cp_rev) = @_;
+       my $gpath = $self->git_path($path);
+       if ($gpath eq '') {
+               my ($ls, $ctx) = command_output_pipe(qw/ls-tree
+                                                    -r --name-only -z/,
+                                                    $self->{c});
+               local $/ = "\0";
+               while (<$ls>) {
+                       chomp;
+                       $self->{gii}->remove($_);
+                       print "\tD\t$_\n" unless $::_q;
+               }
+               command_close_pipe($ls, $ctx);
+               $self->{empty}->{$path} = 0;
+       }
        my ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#);
        delete $self->{empty}->{$dir};
        $self->{empty}->{$path} = 1;
index fffbe9ccb42e305d898a25a126918db0883b11cb..64be904921821c077982f06cea8f66c1954eb420 100644 (file)
@@ -75,7 +75,6 @@ static int aborted;
 static signed char remote_dir_exists[256];
 
 static struct curl_slist *no_pragma_header;
-static struct curl_slist *default_headers;
 
 static int push_verbosely;
 static int push_all = MATCH_REFS_NONE;
@@ -495,10 +494,11 @@ static void start_put(struct transfer_request *request)
        memset(&stream, 0, sizeof(stream));
        deflateInit(&stream, zlib_compression_level);
        size = deflateBound(&stream, len + hdrlen);
-       request->buffer.buffer = xmalloc(size);
+       strbuf_init(&request->buffer.buf, size);
+       request->buffer.posn = 0;
 
        /* Compress it */
-       stream.next_out = request->buffer.buffer;
+       stream.next_out = (unsigned char *)request->buffer.buf.buf;
        stream.avail_out = size;
 
        /* First header.. */
@@ -515,8 +515,7 @@ static void start_put(struct transfer_request *request)
        deflateEnd(&stream);
        free(unpacked);
 
-       request->buffer.size = stream.total_out;
-       request->buffer.posn = 0;
+       request->buffer.buf.len = stream.total_out;
 
        request->url = xmalloc(strlen(remote->url) +
                               strlen(request->lock->token) + 51);
@@ -538,7 +537,7 @@ static void start_put(struct transfer_request *request)
        slot->callback_func = process_response;
        slot->callback_data = request;
        curl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.size);
+       curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.buf.len);
        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
@@ -925,11 +924,14 @@ static int fetch_index(unsigned char *sha1)
                                     hex);
                }
        } else {
+               free(url);
                return error("Unable to start request");
        }
 
-       if (has_pack_index(sha1))
+       if (has_pack_index(sha1)) {
+               free(url);
                return 0;
+       }
 
        if (push_verbosely)
                fprintf(stderr, "Getting index for pack %s\n", hex);
@@ -939,9 +941,11 @@ static int fetch_index(unsigned char *sha1)
        filename = sha1_pack_index_name(sha1);
        snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
        indexfile = fopen(tmpfile, "a");
-       if (!indexfile)
+       if (!indexfile) {
+               free(url);
                return error("Unable to open local file %s for pack index",
                             tmpfile);
+       }
 
        slot = get_active_slot();
        slot->results = &results;
@@ -1003,18 +1007,13 @@ static int fetch_indices(void)
 {
        unsigned char sha1[20];
        char *url;
-       struct buffer buffer;
+       struct strbuf buffer = STRBUF_INIT;
        char *data;
        int i = 0;
 
        struct active_request_slot *slot;
        struct slot_results results;
 
-       data = xcalloc(1, 4096);
-       buffer.size = 4096;
-       buffer.posn = 0;
-       buffer.buffer = data;
-
        if (push_verbosely)
                fprintf(stderr, "Getting pack list\n");
 
@@ -1030,7 +1029,7 @@ static int fetch_indices(void)
        if (start_active_slot(slot)) {
                run_active_slot(slot);
                if (results.curl_result != CURLE_OK) {
-                       free(buffer.buffer);
+                       strbuf_release(&buffer);
                        free(url);
                        if (results.http_code == 404)
                                return 0;
@@ -1038,18 +1037,18 @@ static int fetch_indices(void)
                                return error("%s", curl_errorstr);
                }
        } else {
-               free(buffer.buffer);
+               strbuf_release(&buffer);
                free(url);
                return error("Unable to start request");
        }
        free(url);
 
-       data = buffer.buffer;
-       while (i < buffer.posn) {
+       data = buffer.buf;
+       while (i < buffer.len) {
                switch (data[i]) {
                case 'P':
                        i++;
-                       if (i + 52 < buffer.posn &&
+                       if (i + 52 < buffer.len &&
                            !prefixcmp(data + i, " pack-") &&
                            !prefixcmp(data + i + 46, ".pack\n")) {
                                get_sha1_hex(data + i + 6, sha1);
@@ -1064,89 +1063,10 @@ static int fetch_indices(void)
                i++;
        }
 
-       free(buffer.buffer);
+       strbuf_release(&buffer);
        return 0;
 }
 
-static inline int needs_quote(int ch)
-{
-       if (((ch >= 'A') && (ch <= 'Z'))
-                       || ((ch >= 'a') && (ch <= 'z'))
-                       || ((ch >= '0') && (ch <= '9'))
-                       || (ch == '/')
-                       || (ch == '-')
-                       || (ch == '.'))
-               return 0;
-       return 1;
-}
-
-static inline int hex(int v)
-{
-       if (v < 10) return '0' + v;
-       else return 'A' + v - 10;
-}
-
-static char *quote_ref_url(const char *base, const char *ref)
-{
-       const char *cp;
-       char *dp, *qref;
-       int len, baselen, ch;
-
-       baselen = strlen(base);
-       len = baselen + 1;
-       for (cp = ref; (ch = *cp) != 0; cp++, len++)
-               if (needs_quote(ch))
-                       len += 2; /* extra two hex plus replacement % */
-       qref = xmalloc(len);
-       memcpy(qref, base, baselen);
-       for (cp = ref, dp = qref + baselen; (ch = *cp) != 0; cp++) {
-               if (needs_quote(ch)) {
-                       *dp++ = '%';
-                       *dp++ = hex((ch >> 4) & 0xF);
-                       *dp++ = hex(ch & 0xF);
-               }
-               else
-                       *dp++ = ch;
-       }
-       *dp = 0;
-
-       return qref;
-}
-
-int fetch_ref(char *ref, unsigned char *sha1)
-{
-        char *url;
-        char hex[42];
-        struct buffer buffer;
-       char *base = remote->url;
-       struct active_request_slot *slot;
-       struct slot_results results;
-        buffer.size = 41;
-        buffer.posn = 0;
-        buffer.buffer = hex;
-        hex[41] = '\0';
-
-       url = quote_ref_url(base, ref);
-       slot = get_active_slot();
-       slot->results = &results;
-       curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
-       curl_easy_setopt(slot->curl, CURLOPT_URL, url);
-       if (start_active_slot(slot)) {
-               run_active_slot(slot);
-               if (results.curl_result != CURLE_OK)
-                       return error("Couldn't get %s for %s\n%s",
-                                    url, ref, curl_errorstr);
-       } else {
-               return error("Unable to start request");
-       }
-
-        hex[40] = '\0';
-        get_sha1_hex(hex, sha1);
-        return 0;
-}
-
 static void one_remote_object(const char *hex)
 {
        unsigned char sha1[20];
@@ -1267,10 +1187,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
 {
        struct active_request_slot *slot;
        struct slot_results results;
-       struct buffer out_buffer;
-       struct buffer in_buffer;
-       char *out_data;
-       char *in_data;
+       struct buffer out_buffer = { STRBUF_INIT, 0 };
+       struct strbuf in_buffer = STRBUF_INIT;
        char *url;
        char *ep;
        char timeout_header[25];
@@ -1310,16 +1228,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
                ep = strchr(ep + 1, '/');
        }
 
-       out_buffer.size = strlen(LOCK_REQUEST) + strlen(git_default_email) - 2;
-       out_data = xmalloc(out_buffer.size + 1);
-       snprintf(out_data, out_buffer.size + 1, LOCK_REQUEST, git_default_email);
-       out_buffer.posn = 0;
-       out_buffer.buffer = out_data;
-
-       in_buffer.size = 4096;
-       in_data = xmalloc(in_buffer.size);
-       in_buffer.posn = 0;
-       in_buffer.buffer = in_data;
+       strbuf_addf(&out_buffer.buf, LOCK_REQUEST, git_default_email);
 
        sprintf(timeout_header, "Timeout: Second-%ld", timeout);
        dav_headers = curl_slist_append(dav_headers, timeout_header);
@@ -1328,7 +1237,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
        slot = get_active_slot();
        slot->results = &results;
        curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
+       curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
        curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
@@ -1354,8 +1263,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
                        XML_SetElementHandler(parser, xml_start_tag,
                                              xml_end_tag);
                        XML_SetCharacterDataHandler(parser, xml_cdata);
-                       result = XML_Parse(parser, in_buffer.buffer,
-                                          in_buffer.posn, 1);
+                       result = XML_Parse(parser, in_buffer.buf,
+                                          in_buffer.len, 1);
                        free(ctx.name);
                        if (result != XML_STATUS_OK) {
                                fprintf(stderr, "XML error: %s\n",
@@ -1370,8 +1279,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
        }
 
        curl_slist_free_all(dav_headers);
-       free(out_data);
-       free(in_data);
+       strbuf_release(&out_buffer.buf);
+       strbuf_release(&in_buffer);
 
        if (lock->token == NULL || lock->timeout <= 0) {
                if (lock->token != NULL)
@@ -1522,10 +1431,8 @@ static void remote_ls(const char *path, int flags,
        char *url = xmalloc(strlen(remote->url) + strlen(path) + 1);
        struct active_request_slot *slot;
        struct slot_results results;
-       struct buffer in_buffer;
-       struct buffer out_buffer;
-       char *in_data;
-       char *out_data;
+       struct strbuf in_buffer = STRBUF_INIT;
+       struct buffer out_buffer = { STRBUF_INIT, 0 };
        struct curl_slist *dav_headers = NULL;
        struct xml_ctx ctx;
        struct remote_ls_ctx ls;
@@ -1539,16 +1446,7 @@ static void remote_ls(const char *path, int flags,
 
        sprintf(url, "%s%s", remote->url, path);
 
-       out_buffer.size = strlen(PROPFIND_ALL_REQUEST);
-       out_data = xmalloc(out_buffer.size + 1);
-       snprintf(out_data, out_buffer.size + 1, PROPFIND_ALL_REQUEST);
-       out_buffer.posn = 0;
-       out_buffer.buffer = out_data;
-
-       in_buffer.size = 4096;
-       in_data = xmalloc(in_buffer.size);
-       in_buffer.posn = 0;
-       in_buffer.buffer = in_data;
+       strbuf_addf(&out_buffer.buf, PROPFIND_ALL_REQUEST);
 
        dav_headers = curl_slist_append(dav_headers, "Depth: 1");
        dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
@@ -1556,7 +1454,7 @@ static void remote_ls(const char *path, int flags,
        slot = get_active_slot();
        slot->results = &results;
        curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
+       curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
        curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
@@ -1579,8 +1477,8 @@ static void remote_ls(const char *path, int flags,
                        XML_SetElementHandler(parser, xml_start_tag,
                                              xml_end_tag);
                        XML_SetCharacterDataHandler(parser, xml_cdata);
-                       result = XML_Parse(parser, in_buffer.buffer,
-                                          in_buffer.posn, 1);
+                       result = XML_Parse(parser, in_buffer.buf,
+                                          in_buffer.len, 1);
                        free(ctx.name);
 
                        if (result != XML_STATUS_OK) {
@@ -1596,8 +1494,8 @@ static void remote_ls(const char *path, int flags,
 
        free(ls.path);
        free(url);
-       free(out_data);
-       free(in_buffer.buffer);
+       strbuf_release(&out_buffer.buf);
+       strbuf_release(&in_buffer);
        curl_slist_free_all(dav_headers);
 }
 
@@ -1618,27 +1516,13 @@ static int locking_available(void)
 {
        struct active_request_slot *slot;
        struct slot_results results;
-       struct buffer in_buffer;
-       struct buffer out_buffer;
-       char *in_data;
-       char *out_data;
+       struct strbuf in_buffer = STRBUF_INIT;
+       struct buffer out_buffer = { STRBUF_INIT, 0 };
        struct curl_slist *dav_headers = NULL;
        struct xml_ctx ctx;
        int lock_flags = 0;
 
-       out_buffer.size =
-               strlen(PROPFIND_SUPPORTEDLOCK_REQUEST) +
-               strlen(remote->url) - 2;
-       out_data = xmalloc(out_buffer.size + 1);
-       snprintf(out_data, out_buffer.size + 1,
-                PROPFIND_SUPPORTEDLOCK_REQUEST, remote->url);
-       out_buffer.posn = 0;
-       out_buffer.buffer = out_data;
-
-       in_buffer.size = 4096;
-       in_data = xmalloc(in_buffer.size);
-       in_buffer.posn = 0;
-       in_buffer.buffer = in_data;
+       strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, remote->url);
 
        dav_headers = curl_slist_append(dav_headers, "Depth: 0");
        dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
@@ -1646,7 +1530,7 @@ static int locking_available(void)
        slot = get_active_slot();
        slot->results = &results;
        curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
+       curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
        curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
@@ -1668,8 +1552,8 @@ static int locking_available(void)
                        XML_SetUserData(parser, &ctx);
                        XML_SetElementHandler(parser, xml_start_tag,
                                              xml_end_tag);
-                       result = XML_Parse(parser, in_buffer.buffer,
-                                          in_buffer.posn, 1);
+                       result = XML_Parse(parser, in_buffer.buf,
+                                          in_buffer.len, 1);
                        free(ctx.name);
 
                        if (result != XML_STATUS_OK) {
@@ -1684,8 +1568,8 @@ static int locking_available(void)
                fprintf(stderr, "Unable to start PROPFIND request\n");
        }
 
-       free(out_data);
-       free(in_buffer.buffer);
+       strbuf_release(&out_buffer.buf);
+       strbuf_release(&in_buffer);
        curl_slist_free_all(dav_headers);
 
        return lock_flags;
@@ -1803,30 +1687,20 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
 {
        struct active_request_slot *slot;
        struct slot_results results;
-       char *out_data;
        char *if_header;
-       struct buffer out_buffer;
+       struct buffer out_buffer = { STRBUF_INIT, 0 };
        struct curl_slist *dav_headers = NULL;
-       int i;
 
        if_header = xmalloc(strlen(lock->token) + 25);
        sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
        dav_headers = curl_slist_append(dav_headers, if_header);
 
-       out_buffer.size = 41;
-       out_data = xmalloc(out_buffer.size + 1);
-       i = snprintf(out_data, out_buffer.size + 1, "%s\n", sha1_to_hex(sha1));
-       if (i != out_buffer.size) {
-               fprintf(stderr, "Unable to initialize PUT request body\n");
-               return 0;
-       }
-       out_buffer.posn = 0;
-       out_buffer.buffer = out_data;
+       strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1));
 
        slot = get_active_slot();
        slot->results = &results;
        curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
+       curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
@@ -1837,7 +1711,7 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
 
        if (start_active_slot(slot)) {
                run_active_slot(slot);
-               free(out_data);
+               strbuf_release(&out_buffer.buf);
                free(if_header);
                if (results.curl_result != CURLE_OK) {
                        fprintf(stderr,
@@ -1847,7 +1721,7 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
                        return 0;
                }
        } else {
-               free(out_data);
+               strbuf_release(&out_buffer.buf);
                free(if_header);
                fprintf(stderr, "Unable to start PUT request\n");
                return 0;
@@ -1878,7 +1752,8 @@ static void one_remote_ref(char *refname)
        struct object *obj;
        int len = strlen(refname) + 1;
 
-       if (fetch_ref(refname, remote_sha1) != 0) {
+       if (http_fetch_ref(remote->url, refname + 5 /* "refs/" */,
+                          remote_sha1) != 0) {
                fprintf(stderr,
                        "Unable to fetch ref %s from %s\n",
                        refname, remote->url);
@@ -2004,13 +1879,14 @@ static void mark_edges_uninteresting(struct commit_list *list)
 
 static void add_remote_info_ref(struct remote_ls_ctx *ls)
 {
-       struct buffer *buf = (struct buffer *)ls->userData;
+       struct strbuf *buf = (struct strbuf *)ls->userData;
        unsigned char remote_sha1[20];
        struct object *o;
        int len;
        char *ref_info;
 
-       if (fetch_ref(ls->dentry_name, remote_sha1) != 0) {
+       if (http_fetch_ref(remote->url, ls->dentry_name + 5 /* "refs/" */,
+                          remote_sha1) != 0) {
                fprintf(stderr,
                        "Unable to fetch ref %s from %s\n",
                        ls->dentry_name, remote->url);
@@ -2049,17 +1925,14 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls)
 
 static void update_remote_info_refs(struct remote_lock *lock)
 {
-       struct buffer buffer;
+       struct buffer buffer = { STRBUF_INIT, 0 };
        struct active_request_slot *slot;
        struct slot_results results;
        char *if_header;
        struct curl_slist *dav_headers = NULL;
 
-       buffer.buffer = xcalloc(1, 4096);
-       buffer.size = 4096;
-       buffer.posn = 0;
        remote_ls("refs/", (PROCESS_FILES | RECURSIVE),
-                 add_remote_info_ref, &buffer);
+                 add_remote_info_ref, &buffer.buf);
        if (!aborted) {
                if_header = xmalloc(strlen(lock->token) + 25);
                sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
@@ -2068,7 +1941,7 @@ static void update_remote_info_refs(struct remote_lock *lock)
                slot = get_active_slot();
                slot->results = &results;
                curl_easy_setopt(slot->curl, CURLOPT_INFILE, &buffer);
-               curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.posn);
+               curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.buf.len);
                curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
                curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
                curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
@@ -2077,8 +1950,6 @@ static void update_remote_info_refs(struct remote_lock *lock)
                curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
                curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
 
-               buffer.posn = 0;
-
                if (start_active_slot(slot)) {
                        run_active_slot(slot);
                        if (results.curl_result != CURLE_OK) {
@@ -2089,7 +1960,7 @@ static void update_remote_info_refs(struct remote_lock *lock)
                }
                free(if_header);
        }
-       free(buffer.buffer);
+       strbuf_release(&buffer.buf);
 }
 
 static int remote_exists(const char *path)
@@ -2097,43 +1968,43 @@ static int remote_exists(const char *path)
        char *url = xmalloc(strlen(remote->url) + strlen(path) + 1);
        struct active_request_slot *slot;
        struct slot_results results;
+       int ret = -1;
 
        sprintf(url, "%s%s", remote->url, path);
 
-        slot = get_active_slot();
+       slot = get_active_slot();
        slot->results = &results;
-        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
-        curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
+       curl_easy_setopt(slot->curl, CURLOPT_URL, url);
+       curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
 
-        if (start_active_slot(slot)) {
+       if (start_active_slot(slot)) {
                run_active_slot(slot);
+               free(url);
                if (results.http_code == 404)
-                       return 0;
+                       ret = 0;
                else if (results.curl_result == CURLE_OK)
-                       return 1;
+                       ret = 1;
                else
                        fprintf(stderr, "HEAD HTTP error %ld\n", results.http_code);
        } else {
+               free(url);
                fprintf(stderr, "Unable to start HEAD request\n");
        }
 
-       return -1;
+       free(url);
+       return ret;
 }
 
 static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
 {
        char *url;
-       struct buffer buffer;
+       struct strbuf buffer = STRBUF_INIT;
        struct active_request_slot *slot;
        struct slot_results results;
 
        url = xmalloc(strlen(remote->url) + strlen(path) + 1);
        sprintf(url, "%s%s", remote->url, path);
 
-       buffer.size = 4096;
-       buffer.posn = 0;
-       buffer.buffer = xmalloc(buffer.size);
-
        slot = get_active_slot();
        slot->results = &results;
        curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
@@ -2156,17 +2027,17 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
        *symref = NULL;
        hashclr(sha1);
 
-       if (buffer.posn == 0)
+       if (buffer.len == 0)
                return;
 
        /* If it's a symref, set the refname; otherwise try for a sha1 */
-       if (!prefixcmp((char *)buffer.buffer, "ref: ")) {
-               *symref = xmemdupz((char *)buffer.buffer + 5, buffer.posn - 6);
+       if (!prefixcmp((char *)buffer.buf, "ref: ")) {
+               *symref = xmemdupz((char *)buffer.buf + 5, buffer.len - 6);
        } else {
-               get_sha1_hex(buffer.buffer, sha1);
+               get_sha1_hex(buffer.buf, sha1);
        }
 
-       free(buffer.buffer);
+       strbuf_release(&buffer);
 }
 
 static int verify_merge_base(unsigned char *head_sha1, unsigned char *branch_sha1)
@@ -2354,11 +2225,6 @@ int main(int argc, char **argv)
        http_init();
 
        no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
-       default_headers = curl_slist_append(default_headers, "Range:");
-       default_headers = curl_slist_append(default_headers, "Destination:");
-       default_headers = curl_slist_append(default_headers, "If:");
-       default_headers = curl_slist_append(default_headers,
-                                           "Pragma: no-cache");
 
        /* Verify DAV compliance/lock support */
        if (!locking_available()) {
@@ -2538,7 +2404,6 @@ int main(int argc, char **argv)
        free(remote);
 
        curl_slist_free_all(no_pragma_header);
-       curl_slist_free_all(default_headers);
 
        http_cleanup();
 
index a3fb596542eea6d85a6cb32add100e8d71e7713a..2c3786870e1fbe94a5346cdbc53e6f806011052c 100644 (file)
@@ -48,7 +48,7 @@ struct alternates_request {
        struct walker *walker;
        const char *base;
        char *url;
-       struct buffer *buffer;
+       struct strbuf *buffer;
        struct active_request_slot *slot;
        int http_specific;
 };
@@ -90,19 +90,6 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
        return size;
 }
 
-static int missing__target(int code, int result)
-{
-       return  /* file:// URL -- do we ever use one??? */
-               (result == CURLE_FILE_COULDNT_READ_FILE) ||
-               /* http:// and https:// URL */
-               (code == 404 && result == CURLE_HTTP_RETURNED_ERROR) ||
-               /* ftp:// URL */
-               (code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE)
-               ;
-}
-
-#define missing_target(a) missing__target((a)->http_code, (a)->curl_result)
-
 static void fetch_alternates(struct walker *walker, const char *base);
 
 static void process_object_response(void *callback_data);
@@ -475,7 +462,7 @@ static void process_alternates_response(void *callback_data)
 
        if (alt_req->http_specific) {
                if (slot->curl_result != CURLE_OK ||
-                   !alt_req->buffer->posn) {
+                   !alt_req->buffer->len) {
 
                        /* Try reusing the slot to get non-http alternates */
                        alt_req->http_specific = 0;
@@ -503,12 +490,12 @@ static void process_alternates_response(void *callback_data)
        }
 
        fwrite_buffer(&null_byte, 1, 1, alt_req->buffer);
-       alt_req->buffer->posn--;
-       data = alt_req->buffer->buffer;
+       alt_req->buffer->len--;
+       data = alt_req->buffer->buf;
 
-       while (i < alt_req->buffer->posn) {
+       while (i < alt_req->buffer->len) {
                int posn = i;
-               while (posn < alt_req->buffer->posn && data[posn] != '\n')
+               while (posn < alt_req->buffer->len && data[posn] != '\n')
                        posn++;
                if (data[posn] == '\n') {
                        int okay = 0;
@@ -596,9 +583,8 @@ static void process_alternates_response(void *callback_data)
 
 static void fetch_alternates(struct walker *walker, const char *base)
 {
-       struct buffer buffer;
+       struct strbuf buffer = STRBUF_INIT;
        char *url;
-       char *data;
        struct active_request_slot *slot;
        struct alternates_request alt_req;
        struct walker_data *cdata = walker->data;
@@ -619,11 +605,6 @@ static void fetch_alternates(struct walker *walker, const char *base)
        /* Start the fetch */
        cdata->got_alternates = 0;
 
-       data = xmalloc(4096);
-       buffer.size = 4096;
-       buffer.posn = 0;
-       buffer.buffer = data;
-
        if (walker->get_verbosely)
                fprintf(stderr, "Getting alternates list for %s\n", base);
 
@@ -652,7 +633,7 @@ static void fetch_alternates(struct walker *walker, const char *base)
        else
                cdata->got_alternates = -1;
 
-       free(data);
+       strbuf_release(&buffer);
        free(url);
 }
 
@@ -660,9 +641,10 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)
 {
        unsigned char sha1[20];
        char *url;
-       struct buffer buffer;
+       struct strbuf buffer = STRBUF_INIT;
        char *data;
        int i = 0;
+       int ret = 0;
 
        struct active_request_slot *slot;
        struct slot_results results;
@@ -670,11 +652,6 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)
        if (repo->got_indices)
                return 0;
 
-       data = xmalloc(4096);
-       buffer.size = 4096;
-       buffer.posn = 0;
-       buffer.buffer = data;
-
        if (walker->get_verbosely)
                fprintf(stderr, "Getting pack list for %s\n", repo->base);
 
@@ -692,26 +669,25 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)
                if (results.curl_result != CURLE_OK) {
                        if (missing_target(&results)) {
                                repo->got_indices = 1;
-                               free(buffer.buffer);
-                               return 0;
+                               goto cleanup;
                        } else {
                                repo->got_indices = 0;
-                               free(buffer.buffer);
-                               return error("%s", curl_errorstr);
+                               ret = error("%s", curl_errorstr);
+                               goto cleanup;
                        }
                }
        } else {
                repo->got_indices = 0;
-               free(buffer.buffer);
-               return error("Unable to start request");
+               ret = error("Unable to start request");
+               goto cleanup;
        }
 
-       data = buffer.buffer;
-       while (i < buffer.posn) {
+       data = buffer.buf;
+       while (i < buffer.len) {
                switch (data[i]) {
                case 'P':
                        i++;
-                       if (i + 52 <= buffer.posn &&
+                       if (i + 52 <= buffer.len &&
                            !prefixcmp(data + i, " pack-") &&
                            !prefixcmp(data + i + 46, ".pack\n")) {
                                get_sha1_hex(data + i + 6, sha1);
@@ -720,15 +696,17 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)
                                break;
                        }
                default:
-                       while (i < buffer.posn && data[i] != '\n')
+                       while (i < buffer.len && data[i] != '\n')
                                i++;
                }
                i++;
        }
 
-       free(buffer.buffer);
        repo->got_indices = 1;
-       return 0;
+cleanup:
+       strbuf_release(&buffer);
+       free(url);
+       return ret;
 }
 
 static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
@@ -910,85 +888,10 @@ static int fetch(struct walker *walker, unsigned char *sha1)
                     data->alt->base);
 }
 
-static inline int needs_quote(int ch)
-{
-       if (((ch >= 'A') && (ch <= 'Z'))
-                       || ((ch >= 'a') && (ch <= 'z'))
-                       || ((ch >= '0') && (ch <= '9'))
-                       || (ch == '/')
-                       || (ch == '-')
-                       || (ch == '.'))
-               return 0;
-       return 1;
-}
-
-static inline int hex(int v)
-{
-       if (v < 10) return '0' + v;
-       else return 'A' + v - 10;
-}
-
-static char *quote_ref_url(const char *base, const char *ref)
-{
-       const char *cp;
-       char *dp, *qref;
-       int len, baselen, ch;
-
-       baselen = strlen(base);
-       len = baselen + 7; /* "/refs/" + NUL */
-       for (cp = ref; (ch = *cp) != 0; cp++, len++)
-               if (needs_quote(ch))
-                       len += 2; /* extra two hex plus replacement % */
-       qref = xmalloc(len);
-       memcpy(qref, base, baselen);
-       memcpy(qref + baselen, "/refs/", 6);
-       for (cp = ref, dp = qref + baselen + 6; (ch = *cp) != 0; cp++) {
-               if (needs_quote(ch)) {
-                       *dp++ = '%';
-                       *dp++ = hex((ch >> 4) & 0xF);
-                       *dp++ = hex(ch & 0xF);
-               }
-               else
-                       *dp++ = ch;
-       }
-       *dp = 0;
-
-       return qref;
-}
-
 static int fetch_ref(struct walker *walker, char *ref, unsigned char *sha1)
 {
-        char *url;
-        char hex[42];
-        struct buffer buffer;
        struct walker_data *data = walker->data;
-       const char *base = data->alt->base;
-       struct active_request_slot *slot;
-       struct slot_results results;
-        buffer.size = 41;
-        buffer.posn = 0;
-        buffer.buffer = hex;
-        hex[41] = '\0';
-
-       url = quote_ref_url(base, ref);
-       slot = get_active_slot();
-       slot->results = &results;
-       curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
-       curl_easy_setopt(slot->curl, CURLOPT_URL, url);
-       if (start_active_slot(slot)) {
-               run_active_slot(slot);
-               if (results.curl_result != CURLE_OK)
-                       return error("Couldn't get %s for %s\n%s",
-                                    url, ref, curl_errorstr);
-       } else {
-               return error("Unable to start request");
-       }
-
-        hex[40] = '\0';
-        get_sha1_hex(hex, sha1);
-        return 0;
+       return http_fetch_ref(data->alt->base, ref, sha1);
 }
 
 static void cleanup(struct walker *walker)
diff --git a/http.c b/http.c
index 146f62609dbf75cf8b6d873f040e1386d73b57d1..d2c11aee9077e0834c5c56b1284df478eb8debbc 100644 (file)
--- a/http.c
+++ b/http.c
@@ -34,31 +34,25 @@ size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb,
                           struct buffer *buffer)
 {
        size_t size = eltsize * nmemb;
-       if (size > buffer->size - buffer->posn)
-               size = buffer->size - buffer->posn;
-       memcpy(ptr, (char *) buffer->buffer + buffer->posn, size);
+       if (size > buffer->buf.len - buffer->posn)
+               size = buffer->buf.len - buffer->posn;
+       memcpy(ptr, buffer->buf.buf + buffer->posn, size);
        buffer->posn += size;
+
        return size;
 }
 
 size_t fwrite_buffer(const void *ptr, size_t eltsize,
-                           size_t nmemb, struct buffer *buffer)
+                           size_t nmemb, struct strbuf *buffer)
 {
        size_t size = eltsize * nmemb;
-       if (size > buffer->size - buffer->posn) {
-               buffer->size = buffer->size * 3 / 2;
-               if (buffer->size < buffer->posn + size)
-                       buffer->size = buffer->posn + size;
-               buffer->buffer = xrealloc(buffer->buffer, buffer->size);
-       }
-       memcpy((char *) buffer->buffer + buffer->posn, ptr, size);
-       buffer->posn += size;
+       strbuf_add(buffer, ptr, size);
        data_received++;
        return size;
 }
 
 size_t fwrite_null(const void *ptr, size_t eltsize,
-                         size_t nmemb, struct buffer *buffer)
+                         size_t nmemb, struct strbuf *buffer)
 {
        data_received++;
        return eltsize * nmemb;
@@ -370,7 +364,6 @@ struct active_request_slot *get_active_slot(void)
        slot->finished = NULL;
        slot->callback_data = NULL;
        slot->callback_func = NULL;
-       curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
        curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);
@@ -508,8 +501,8 @@ void run_active_slot(struct active_request_slot *slot)
 
 static void closedown_active_slot(struct active_request_slot *slot)
 {
-        active_requests--;
-        slot->in_use = 0;
+       active_requests--;
+       slot->in_use = 0;
 }
 
 void release_active_slot(struct active_request_slot *slot)
@@ -530,7 +523,7 @@ void release_active_slot(struct active_request_slot *slot)
 static void finish_active_slot(struct active_request_slot *slot)
 {
        closedown_active_slot(slot);
-        curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
+       curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
 
        if (slot->finished != NULL)
                (*slot->finished) = 1;
@@ -541,10 +534,10 @@ static void finish_active_slot(struct active_request_slot *slot)
                slot->results->http_code = slot->http_code;
        }
 
-        /* Run callback if appropriate */
-        if (slot->callback_func != NULL) {
-                slot->callback_func(slot->callback_data);
-        }
+       /* Run callback if appropriate */
+       if (slot->callback_func != NULL) {
+               slot->callback_func(slot->callback_data);
+       }
 }
 
 void finish_all_active_slots(void)
@@ -559,3 +552,85 @@ void finish_all_active_slots(void)
                        slot = slot->next;
                }
 }
+
+static inline int needs_quote(int ch)
+{
+       if (((ch >= 'A') && (ch <= 'Z'))
+                       || ((ch >= 'a') && (ch <= 'z'))
+                       || ((ch >= '0') && (ch <= '9'))
+                       || (ch == '/')
+                       || (ch == '-')
+                       || (ch == '.'))
+               return 0;
+       return 1;
+}
+
+static inline int hex(int v)
+{
+       if (v < 10) return '0' + v;
+       else return 'A' + v - 10;
+}
+
+static char *quote_ref_url(const char *base, const char *ref)
+{
+       const char *cp;
+       char *dp, *qref;
+       int len, baselen, ch;
+
+       baselen = strlen(base);
+       len = baselen + 7; /* "/refs/" + NUL */
+       for (cp = ref; (ch = *cp) != 0; cp++, len++)
+               if (needs_quote(ch))
+                       len += 2; /* extra two hex plus replacement % */
+       qref = xmalloc(len);
+       memcpy(qref, base, baselen);
+       memcpy(qref + baselen, "/refs/", 6);
+       for (cp = ref, dp = qref + baselen + 6; (ch = *cp) != 0; cp++) {
+               if (needs_quote(ch)) {
+                       *dp++ = '%';
+                       *dp++ = hex((ch >> 4) & 0xF);
+                       *dp++ = hex(ch & 0xF);
+               }
+               else
+                       *dp++ = ch;
+       }
+       *dp = 0;
+
+       return qref;
+}
+
+int http_fetch_ref(const char *base, const char *ref, unsigned char *sha1)
+{
+       char *url;
+       struct strbuf buffer = STRBUF_INIT;
+       struct active_request_slot *slot;
+       struct slot_results results;
+       int ret;
+
+       url = quote_ref_url(base, ref);
+       slot = get_active_slot();
+       slot->results = &results;
+       curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
+       curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
+       curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
+       curl_easy_setopt(slot->curl, CURLOPT_URL, url);
+       if (start_active_slot(slot)) {
+               run_active_slot(slot);
+               if (results.curl_result == CURLE_OK) {
+                       strbuf_rtrim(&buffer);
+                       if (buffer.len == 40)
+                               ret = get_sha1_hex(buffer.buf, sha1);
+                       else
+                               ret = 1;
+               } else {
+                       ret = error("Couldn't get %s for %s\n%s",
+                                   url, ref, curl_errorstr);
+               }
+       } else {
+               ret = error("Unable to start request");
+       }
+
+       strbuf_release(&buffer);
+       free(url);
+       return ret;
+}
diff --git a/http.h b/http.h
index fe1b0d153bcd80d12a405c26e0f073cbf14dde34..aeba9301f8fe1a1d4e2f9819257579375be648aa 100644 (file)
--- a/http.h
+++ b/http.h
@@ -6,6 +6,8 @@
 #include <curl/curl.h>
 #include <curl/easy.h>
 
+#include "strbuf.h"
+
 #if LIBCURL_VERSION_NUM >= 0x071000
 #define USE_CURL_MULTI
 #define DEFAULT_MAX_REQUESTS 5
@@ -48,18 +50,17 @@ struct active_request_slot
 
 struct buffer
 {
-        size_t posn;
-        size_t size;
-        void *buffer;
+       struct strbuf buf;
+       size_t posn;
 };
 
 /* Curl request read/write callbacks */
 extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb,
                           struct buffer *buffer);
 extern size_t fwrite_buffer(const void *ptr, size_t eltsize,
-                           size_t nmemb, struct buffer *buffer);
+                           size_t nmemb, struct strbuf *buffer);
 extern size_t fwrite_null(const void *ptr, size_t eltsize,
-                         size_t nmemb, struct buffer *buffer);
+                         size_t nmemb, struct strbuf *buffer);
 
 /* Slot lifecycle functions */
 extern struct active_request_slot *get_active_slot(void);
@@ -82,4 +83,19 @@ extern int active_requests;
 
 extern char curl_errorstr[CURL_ERROR_SIZE];
 
+static inline int missing__target(int code, int result)
+{
+       return  /* file:// URL -- do we ever use one??? */
+               (result == CURLE_FILE_COULDNT_READ_FILE) ||
+               /* http:// and https:// URL */
+               (code == 404 && result == CURLE_HTTP_RETURNED_ERROR) ||
+               /* ftp:// URL */
+               (code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE)
+               ;
+}
+
+#define missing_target(a) missing__target((a)->http_code, (a)->curl_result)
+
+extern int http_fetch_ref(const char *base, const char *ref, unsigned char *sha1);
+
 #endif /* HTTP_H */
index 3fb0f99b29e7ffd927abf166cfa004c1937aaf60..0e006804ef3cc190fa286c85e2de034a33791886 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -220,11 +220,11 @@ static int handle_config(const char *key, const char *value)
        if (!prefixcmp(key, "branch.")) {
                name = key + 7;
                subkey = strrchr(name, '.');
-               branch = make_branch(name, subkey - name);
                if (!subkey)
                        return 0;
                if (!value)
                        return 0;
+               branch = make_branch(name, subkey - name);
                if (!strcmp(subkey, ".remote")) {
                        branch->remote_name = xstrdup(value);
                        if (branch == current_branch)
index 05aa97d6f3d3a87d94004b9f9f4394d8e35175f6..d1a415a12624f4a116a9001bad48c34420671280 100755 (executable)
@@ -310,4 +310,21 @@ test_expect_success 'same tree (merge and amend merge)' '
 
 '
 
+test_expect_success 'amend using the message from another commit' '
+
+       git reset --hard &&
+       test_tick &&
+       git commit --allow-empty -m "old commit" &&
+       old=$(git rev-parse --verify HEAD) &&
+       test_tick &&
+       git commit --allow-empty -m "new commit" &&
+       new=$(git rev-parse --verify HEAD) &&
+       test_tick &&
+       git commit --allow-empty --amend -C "$old" &&
+       git show --pretty="format:%ad %s" "$old" >expected &&
+       git show --pretty="format:%ad %s" HEAD >actual &&
+       diff -u expected actual
+
+'
+
 test_done
diff --git a/t/t9103-git-svn-tracked-directory-removed.sh b/t/t9103-git-svn-tracked-directory-removed.sh
new file mode 100755 (executable)
index 0000000..0f0b0fd
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Eric Wong
+#
+
+test_description='git-svn tracking removed top-level path'
+. ./lib-git-svn.sh
+
+test_expect_success 'make history for tracking' '
+       mkdir import &&
+       mkdir import/trunk &&
+       echo hello >> import/trunk/README &&
+       svn import -m initial import $svnrepo &&
+       rm -rf import &&
+       svn co $svnrepo/trunk trunk &&
+       echo bye bye >> trunk/README &&
+       svn rm -m "gone" $svnrepo/trunk &&
+       rm -rf trunk &&
+       mkdir trunk &&
+       echo "new" > trunk/FOLLOWME &&
+       svn import -m "new trunk" trunk $svnrepo/trunk
+'
+
+test_expect_success 'clone repo with git' '
+       git svn clone -s $svnrepo x &&
+       test -f x/FOLLOWME &&
+       test ! -f x/README
+'
+
+test_expect_success 'make sure r2 still has old file' '
+       cd x &&
+               test -n "$(git svn find-rev r1)" &&
+               git reset --hard $(git svn find-rev r1) &&
+               test -f README &&
+               test ! -f FOLLOWME &&
+               test x$(git svn find-rev r2) = x
+'
+
+test_done
index 58e66f6c11798dac416941ce5ad3dbae91c31a06..4e151a9e878b402fd0b70c31057b9bcfcff7d9b7 100644 (file)
@@ -426,22 +426,9 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
        return !!err;
 }
 
-static int missing__target(int code, int result)
-{
-       return  /* file:// URL -- do we ever use one??? */
-               (result == CURLE_FILE_COULDNT_READ_FILE) ||
-               /* http:// and https:// URL */
-               (code == 404 && result == CURLE_HTTP_RETURNED_ERROR) ||
-               /* ftp:// URL */
-               (code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE)
-               ;
-}
-
-#define missing_target(a) missing__target((a)->http_code, (a)->curl_result)
-
 static struct ref *get_refs_via_curl(struct transport *transport)
 {
-       struct buffer buffer;
+       struct strbuf buffer = STRBUF_INIT;
        char *data, *start, *mid;
        char *ref_name;
        char *refs_url;
@@ -454,11 +441,6 @@ static struct ref *get_refs_via_curl(struct transport *transport)
        struct ref *ref = NULL;
        struct ref *last_ref = NULL;
 
-       data = xmalloc(4096);
-       buffer.size = 4096;
-       buffer.posn = 0;
-       buffer.buffer = data;
-
        refs_url = xmalloc(strlen(transport->url) + 11);
        sprintf(refs_url, "%s/info/refs", transport->url);
 
@@ -477,27 +459,26 @@ static struct ref *get_refs_via_curl(struct transport *transport)
        if (start_active_slot(slot)) {
                run_active_slot(slot);
                if (results.curl_result != CURLE_OK) {
+                       strbuf_release(&buffer);
                        if (missing_target(&results)) {
-                               free(buffer.buffer);
                                return NULL;
                        } else {
-                               free(buffer.buffer);
                                error("%s", curl_errorstr);
                                return NULL;
                        }
                }
        } else {
-               free(buffer.buffer);
+               strbuf_release(&buffer);
                error("Unable to start request");
                return NULL;
        }
 
        http_cleanup();
 
-       data = buffer.buffer;
+       data = buffer.buf;
        start = NULL;
        mid = data;
-       while (i < buffer.posn) {
+       while (i < buffer.len) {
                if (!start)
                        start = &data[i];
                if (data[i] == '\t')
@@ -520,7 +501,7 @@ static struct ref *get_refs_via_curl(struct transport *transport)
                i++;
        }
 
-       free(buffer.buffer);
+       strbuf_release(&buffer);
 
        return refs;
 }
index f2cd488de03beabea4bae32b69008157612618e4..700def211e25a61591d4609ef19d64d91319f33e 100644 (file)
@@ -107,11 +107,10 @@ int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
  * Trim down common substring at the end of the buffers,
  * but leave at least ctx lines at the end.
  */
-static void trim_common_tail(mmfile_t *a, mmfile_t *b, int ctx)
+static void trim_common_tail(mmfile_t *a, mmfile_t *b, long ctx)
 {
        const int blk = 1024;
-       long trimmed = 0, recovered = 0;
-       int i;
+       long trimmed = 0, recovered = 0, i;
        char *ap = a->ptr + a->size;
        char *bp = b->ptr + b->size;
        long smaller = (a->size < b->size) ? a->size : b->size;