Code

Merge branch 'lt/objformat'
authorJunio C Hamano <junkio@cox.net>
Tue, 25 Jul 2006 00:38:03 +0000 (17:38 -0700)
committerJunio C Hamano <junkio@cox.net>
Tue, 25 Jul 2006 00:38:03 +0000 (17:38 -0700)
* lt/objformat:
  sha1_file: add the ability to parse objects in "pack file format"

1  2 
Documentation/config.txt
sha1_file.c

diff --combined Documentation/config.txt
index 9d08dfcedadc8146dc9521212ac078fcb99d57ab,9780c89bc34408c7127ddead848cf6fd6f6274a4..465eb13e76dca5cf4daad9d5ea773f4743452c75
@@@ -97,6 -97,12 +97,12 @@@ core.compression:
        compression, and 1..9 are various speed/size tradeoffs, 9 being
        slowest.
  
+ core.legacyheaders::
+       A boolean which enables the legacy object header format in case
+       you want to interoperate with old clients accessing the object
+       database directly (where the "http://" and "rsync://" protocols
+       count as direct access).
  alias.*::
        Command aliases for the gitlink:git[1] command wrapper - e.g.
        after defining "alias.last = cat-file commit HEAD", the invocation
@@@ -193,10 -199,6 +199,10 @@@ merge.summary:
        Whether to include summaries of merged commits in newly created
        merge commit messages. False by default.
  
 +pack.window::
 +      The size of the window used by gitlink:git-pack-objects[1] when no
 +      window size is given on the command line. Defaults to 10.
 +
  pull.octopus::
        The default merge strategy to use when pulling multiple branches
        at once.
@@@ -212,17 -214,6 +218,17 @@@ showbranch.default:
        The default set of branches for gitlink:git-show-branch[1].
        See gitlink:git-show-branch[1].
  
 +tar.umask::
 +      By default, git-link:git-tar-tree[1] sets file and directories modes
 +      to 0666 or 0777. While this is both useful and acceptable for projects
 +      such as the Linux Kernel, it might be excessive for other projects.
 +      With this variable, it becomes possible to tell
 +      git-link:git-tar-tree[1] to apply a specific umask to the modes above.
 +      The special value "user" indicates that the user's current umask will
 +      be used. This should be enough for most projects, as it will lead to
 +      the same permissions as git-link:git-checkout[1] would use. The default
 +      value remains 0, which means world read-write.
 +
  user.email::
        Your email address to be recorded in any newly created commits.
        Can be overridden by the 'GIT_AUTHOR_EMAIL' and 'GIT_COMMITTER_EMAIL'
diff --combined sha1_file.c
index e666aec502f1aaadac62c72c152beeab15a8bd8e,88a2579412336dae3ae456de05a20fb53b71c116..43bc2ea0cf039bb9fd02c8313981e85bd7398d33
@@@ -684,26 -684,74 +684,74 @@@ static void *map_sha1_file_internal(con
        return map;
  }
  
- static int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size)
+ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
  {
+       unsigned char c;
+       unsigned int word, bits;
+       unsigned long size;
+       static const char *typename[8] = {
+               NULL,   /* OBJ_EXT */
+               "commit", "tree", "blob", "tag",
+               NULL, NULL, NULL
+       };
+       const char *type;
        /* Get the data stream */
        memset(stream, 0, sizeof(*stream));
        stream->next_in = map;
        stream->avail_in = mapsize;
        stream->next_out = buffer;
-       stream->avail_out = size;
+       stream->avail_out = bufsiz;
+       /*
+        * Is it a zlib-compressed buffer? If so, the first byte
+        * must be 0x78 (15-bit window size, deflated), and the
+        * first 16-bit word is evenly divisible by 31
+        */
+       word = (map[0] << 8) + map[1];
+       if (map[0] == 0x78 && !(word % 31)) {
+               inflateInit(stream);
+               return inflate(stream, 0);
+       }
+       c = *map++;
+       mapsize--;
+       type = typename[(c >> 4) & 7];
+       if (!type)
+               return -1;
  
+       bits = 4;
+       size = c & 0xf;
+       while ((c & 0x80)) {
+               if (bits >= 8*sizeof(long))
+                       return -1;
+               c = *map++;
+               size += (c & 0x7f) << bits;
+               bits += 7;
+               mapsize--;
+       }
+       /* Set up the stream for the rest.. */
+       stream->next_in = map;
+       stream->avail_in = mapsize;
        inflateInit(stream);
-       return inflate(stream, 0);
+       /* And generate the fake traditional header */
+       stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu", type, size);
+       return 0;
  }
  
  static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size)
  {
        int bytes = strlen(buffer) + 1;
        unsigned char *buf = xmalloc(1+size);
+       unsigned long n;
  
-       memcpy(buf, (char *) buffer + bytes, stream->total_out - bytes);
-       bytes = stream->total_out - bytes;
+       n = stream->total_out - bytes;
+       if (n > size)
+               n = size;
+       memcpy(buf, (char *) buffer + bytes, n);
+       bytes = n;
        if (bytes < size) {
                stream->next_out = buf + bytes;
                stream->avail_out = size - bytes;
@@@ -1331,29 -1379,31 +1379,29 @@@ char *write_sha1_file_prepare(void *buf
  static int link_temp_to_file(const char *tmpfile, char *filename)
  {
        int ret;
 +      char *dir;
  
        if (!link(tmpfile, filename))
                return 0;
  
        /*
 -       * Try to mkdir the last path component if that failed
 -       * with an ENOENT.
 +       * Try to mkdir the last path component if that failed.
         *
         * Re-try the "link()" regardless of whether the mkdir
         * succeeds, since a race might mean that somebody
         * else succeeded.
         */
        ret = errno;
 -      if (ret == ENOENT) {
 -              char *dir = strrchr(filename, '/');
 -              if (dir) {
 -                      *dir = 0;
 -                      mkdir(filename, 0777);
 -                      if (adjust_shared_perm(filename))
 -                              return -2;
 -                      *dir = '/';
 -                      if (!link(tmpfile, filename))
 -                              return 0;
 -                      ret = errno;
 -              }
 +      dir = strrchr(filename, '/');
 +      if (dir) {
 +              *dir = 0;
 +              mkdir(filename, 0777);
 +              if (adjust_shared_perm(filename))
 +                      return -2;
 +              *dir = '/';
 +              if (!link(tmpfile, filename))
 +                      return 0;
 +              ret = errno;
        }
        return ret;
  }
@@@ -1412,6 -1462,49 +1460,49 @@@ static int write_buffer(int fd, const v
        return 0;
  }
  
+ static int write_binary_header(unsigned char *hdr, enum object_type type, unsigned long len)
+ {
+       int hdr_len;
+       unsigned char c;
+       c = (type << 4) | (len & 15);
+       len >>= 4;
+       hdr_len = 1;
+       while (len) {
+               *hdr++ = c | 0x80;
+               hdr_len++;
+               c = (len & 0x7f);
+               len >>= 7;
+       }
+       *hdr = c;
+       return hdr_len;
+ }
+ static void setup_object_header(z_stream *stream, const char *type, unsigned long len)
+ {
+       int obj_type, hdr;
+       if (use_legacy_headers) {
+               while (deflate(stream, 0) == Z_OK)
+                       /* nothing */;
+               return;
+       }
+       if (!strcmp(type, blob_type))
+               obj_type = OBJ_BLOB;
+       else if (!strcmp(type, tree_type))
+               obj_type = OBJ_TREE;
+       else if (!strcmp(type, commit_type))
+               obj_type = OBJ_COMMIT;
+       else if (!strcmp(type, tag_type))
+               obj_type = OBJ_TAG;
+       else
+               die("trying to generate bogus object of type '%s'", type);
+       hdr = write_binary_header(stream->next_out, obj_type, len);
+       stream->total_out = hdr;
+       stream->next_out += hdr;
+       stream->avail_out -= hdr;
+ }
  int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
  {
        int size;
        /* Set it up */
        memset(&stream, 0, sizeof(stream));
        deflateInit(&stream, zlib_compression_level);
-       size = deflateBound(&stream, len+hdrlen);
+       size = 8 + deflateBound(&stream, len+hdrlen);
        compressed = xmalloc(size);
  
        /* Compress it */
        /* First header.. */
        stream.next_in = hdr;
        stream.avail_in = hdrlen;
-       while (deflate(&stream, 0) == Z_OK)
-               /* nothing */;
+       setup_object_header(&stream, type, len);
  
        /* Then the data itself.. */
        stream.next_in = buf;