Merge branch 'jl/daemon'
authorJunio C Hamano <junkio@cox.net>
Sun, 24 Sep 2006 23:58:34 +0000 (16:58 -0700)
committerJunio C Hamano <junkio@cox.net>
Sun, 24 Sep 2006 23:58:34 +0000 (16:58 -0700)
* jl/daemon:
Add virtualization support to git-daemon

23 files changed:
.gitignore
Documentation/config.txt
Documentation/git-init-db.txt
Documentation/git-receive-pack.txt
Documentation/git-zip-tree.txt [deleted file]
Makefile
archive-zip.c [new file with mode: 0644]
builtin-init-db.c
builtin-mailinfo.c
builtin-upload-archive.c
builtin-zip-tree.c [deleted file]
builtin.h
cache.h
environment.c
git-resolve.sh
git.c
gitweb/gitweb.perl
receive-pack.c
setup.c
sha1_file.c
sha1_name.c
t/t5400-send-pack.sh
t/test-lib.sh
index a3d9c7a11dc8e2807db377090fd1d4144aad0056..3ca66e42fdbc0b4df11d38867e6d1faa7c9d5172 100644 (file)
@@ -128,7 +128,6 @@ git-verify-pack
 git-verify-tag
 git-whatchanged
 git-write-tree
-git-zip-tree
 git-core-*/?*
 gitweb/gitweb.cgi
 test-date
index 844cae4cf024b17206021d1c55819922cf99277d..bb2fbc324e6fa93a639b31668a7a030ece7787f0 100644 (file)
@@ -267,3 +267,10 @@ whatchanged.difftree::
 imap::
        The configuration variables in the 'imap' section are described
        in gitlink:git-imap-send[1].
+
+receive.denyNonFastforwads::
+       If set to true, git-receive-pack will deny a ref update which is
+       not a fast forward. Use this to prevent such an update via a push,
+       even if that push is forced. This configuration variable is
+       set when initializing a shared repository.
+
index 63cd5dab3f82746816d6dc0b8eae32f2c9d930d4..ca7d09dc0a8563a1d8005bc83a89d19c785c1a3d 100644 (file)
@@ -48,6 +48,10 @@ is given:
  - 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
    readable by all users.
 
+By default, the configuration flag receive.denyNonFastforward is enabled
+in shared repositories, so that you cannot force a non fast-forwarding push
+into it.
+
 --
 
 
index f9457d45ed684597769124af945c184a7d03a948..0dfadc2a32a44ef1e026ae95c8cc5906ec4d4d5c 100644 (file)
@@ -73,6 +73,8 @@ packed and is served via a dumb transport.
 There are other real-world examples of using update and
 post-update hooks found in the Documentation/howto directory.
 
+git-receive-pack honours the receive.denyNonFastforwards flag, which
+tells it if updates to a ref should be denied if they are not fast-forwards.
 
 OPTIONS
 -------
diff --git a/Documentation/git-zip-tree.txt b/Documentation/git-zip-tree.txt
deleted file mode 100644 (file)
index 2e9d981..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-git-zip-tree(1)
-===============
-
-NAME
-----
-git-zip-tree - Creates a ZIP archive of the files in the named tree
-
-
-SYNOPSIS
---------
-'git-zip-tree' [-0|...|-9] <tree-ish> [ <base> ]
-
-DESCRIPTION
------------
-Creates a ZIP archive containing the tree structure for the named tree.
-When <base> is specified it is added as a leading path to the files in the
-generated ZIP archive.
-
-git-zip-tree behaves differently when given a tree ID versus when given
-a commit ID or tag ID.  In the first case the current time is used as
-modification time of each file in the archive.  In the latter case the
-commit time as recorded in the referenced commit object is used instead.
-Additionally the commit ID is stored as an archive comment.
-
-Currently git-zip-tree can handle only files and directories, symbolic
-links are not supported.
-
-OPTIONS
--------
-
--0::
-       Store the files instead of deflating them.
-
--9::
-       Highest and slowest compression level.  You can specify any
-       number from 1 to 9 to adjust compression speed and ratio.
-
-<tree-ish>::
-       The tree or commit to produce ZIP archive for.  If it is
-       the object name of a commit object.
-
-<base>::
-       Leading path to the files in the resulting ZIP archive.
-
-EXAMPLES
---------
-git zip-tree v1.4.0 git-1.4.0 >git-1.4.0.zip::
-
-       Create a ZIP file for v1.4.0 release.
-
-git zip-tree HEAD:Documentation/ git-docs >docs.zip::
-
-       Put everything in the current head's Documentation/ directory
-       into 'docs.zip', with the prefix 'git-docs/'.
-
-Author
-------
-Written by Rene Scharfe.
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
-
index fb2ade5afbe69f66918e95fd02f069f0bb4ef9d2..4a8cd22602828cd7ae5efb74a3798b7e641a1b04 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -256,7 +256,7 @@ LIB_OBJS = \
        fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
        write_or_die.o trace.o list-objects.o \
        alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
-       color.o wt-status.o
+       color.o wt-status.o archive-zip.o
 
 BUILTIN_OBJS = \
        builtin-add.o \
@@ -302,8 +302,7 @@ BUILTIN_OBJS = \
        builtin-upload-archive.o \
        builtin-upload-tar.o \
        builtin-verify-pack.o \
-       builtin-write-tree.o \
-       builtin-zip-tree.o
+       builtin-write-tree.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 LIBS = $(GITLIBS) -lz
diff --git a/archive-zip.c b/archive-zip.c
new file mode 100644 (file)
index 0000000..3ffdad6
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2006 Rene Scharfe
+ */
+#include <time.h>
+#include "cache.h"
+#include "commit.h"
+#include "blob.h"
+#include "tree.h"
+#include "quote.h"
+#include "builtin.h"
+#include "archive.h"
+
+static int verbose;
+static int zip_date;
+static int zip_time;
+
+static unsigned char *zip_dir;
+static unsigned int zip_dir_size;
+
+static unsigned int zip_offset;
+static unsigned int zip_dir_offset;
+static unsigned int zip_dir_entries;
+
+#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
+
+struct zip_local_header {
+       unsigned char magic[4];
+       unsigned char version[2];
+       unsigned char flags[2];
+       unsigned char compression_method[2];
+       unsigned char mtime[2];
+       unsigned char mdate[2];
+       unsigned char crc32[4];
+       unsigned char compressed_size[4];
+       unsigned char size[4];
+       unsigned char filename_length[2];
+       unsigned char extra_length[2];
+};
+
+struct zip_dir_header {
+       unsigned char magic[4];
+       unsigned char creator_version[2];
+       unsigned char version[2];
+       unsigned char flags[2];
+       unsigned char compression_method[2];
+       unsigned char mtime[2];
+       unsigned char mdate[2];
+       unsigned char crc32[4];
+       unsigned char compressed_size[4];
+       unsigned char size[4];
+       unsigned char filename_length[2];
+       unsigned char extra_length[2];
+       unsigned char comment_length[2];
+       unsigned char disk[2];
+       unsigned char attr1[2];
+       unsigned char attr2[4];
+       unsigned char offset[4];
+};
+
+struct zip_dir_trailer {
+       unsigned char magic[4];
+       unsigned char disk[2];
+       unsigned char directory_start_disk[2];
+       unsigned char entries_on_this_disk[2];
+       unsigned char entries[2];
+       unsigned char size[4];
+       unsigned char offset[4];
+       unsigned char comment_length[2];
+};
+
+static void copy_le16(unsigned char *dest, unsigned int n)
+{
+       dest[0] = 0xff & n;
+       dest[1] = 0xff & (n >> 010);
+}
+
+static void copy_le32(unsigned char *dest, unsigned int n)
+{
+       dest[0] = 0xff & n;
+       dest[1] = 0xff & (n >> 010);
+       dest[2] = 0xff & (n >> 020);
+       dest[3] = 0xff & (n >> 030);
+}
+
+static void *zlib_deflate(void *data, unsigned long size,
+                          unsigned long *compressed_size)
+{
+       z_stream stream;
+       unsigned long maxsize;
+       void *buffer;
+       int result;
+
+       memset(&stream, 0, sizeof(stream));
+       deflateInit(&stream, zlib_compression_level);
+       maxsize = deflateBound(&stream, size);
+       buffer = xmalloc(maxsize);
+
+       stream.next_in = data;
+       stream.avail_in = size;
+       stream.next_out = buffer;
+       stream.avail_out = maxsize;
+
+       do {
+               result = deflate(&stream, Z_FINISH);
+       } while (result == Z_OK);
+
+       if (result != Z_STREAM_END) {
+               free(buffer);
+               return NULL;
+       }
+
+       deflateEnd(&stream);
+       *compressed_size = stream.total_out;
+
+       return buffer;
+}
+
+static char *construct_path(const char *base, int baselen,
+                            const char *filename, int isdir, int *pathlen)
+{
+       int filenamelen = strlen(filename);
+       int len = baselen + filenamelen;
+       char *path, *p;
+
+       if (isdir)
+               len++;
+       p = path = xmalloc(len + 1);
+
+       memcpy(p, base, baselen);
+       p += baselen;
+       memcpy(p, filename, filenamelen);
+       p += filenamelen;
+       if (isdir)
+               *p++ = '/';
+       *p = '\0';
+
+       *pathlen = len;
+
+       return path;
+}
+
+static int write_zip_entry(const unsigned char *sha1,
+                           const char *base, int baselen,
+                           const char *filename, unsigned mode, int stage)
+{
+       struct zip_local_header header;
+       struct zip_dir_header dirent;
+       unsigned long compressed_size;
+       unsigned long uncompressed_size;
+       unsigned long crc;
+       unsigned long direntsize;
+       unsigned long size;
+       int method;
+       int result = -1;
+       int pathlen;
+       unsigned char *out;
+       char *path;
+       char type[20];
+       void *buffer = NULL;
+       void *deflated = NULL;
+
+       crc = crc32(0, Z_NULL, 0);
+
+       path = construct_path(base, baselen, filename, S_ISDIR(mode), &pathlen);
+       if (verbose)
+               fprintf(stderr, "%s\n", path);
+       if (pathlen > 0xffff) {
+               error("path too long (%d chars, SHA1: %s): %s", pathlen,
+                     sha1_to_hex(sha1), path);
+               goto out;
+       }
+
+       if (S_ISDIR(mode)) {
+               method = 0;
+               result = READ_TREE_RECURSIVE;
+               out = NULL;
+               uncompressed_size = 0;
+               compressed_size = 0;
+       } else if (S_ISREG(mode)) {
+               method = zlib_compression_level == 0 ? 0 : 8;
+               result = 0;
+               buffer = read_sha1_file(sha1, type, &size);
+               if (!buffer)
+                       die("cannot read %s", sha1_to_hex(sha1));
+               crc = crc32(crc, buffer, size);
+               out = buffer;
+               uncompressed_size = size;
+               compressed_size = size;
+       } else {
+               error("unsupported file mode: 0%o (SHA1: %s)", mode,
+                     sha1_to_hex(sha1));
+               goto out;
+       }
+
+       if (method == 8) {
+               deflated = zlib_deflate(buffer, size, &compressed_size);
+               if (deflated && compressed_size - 6 < size) {
+                       /* ZLIB --> raw compressed data (see RFC 1950) */
+                       /* CMF and FLG ... */
+                       out = (unsigned char *)deflated + 2;
+                       compressed_size -= 6;   /* ... and ADLER32 */
+               } else {
+                       method = 0;
+                       compressed_size = size;
+               }
+       }
+
+       /* make sure we have enough free space in the dictionary */
+       direntsize = sizeof(struct zip_dir_header) + pathlen;
+       while (zip_dir_size < zip_dir_offset + direntsize) {
+               zip_dir_size += ZIP_DIRECTORY_MIN_SIZE;
+               zip_dir = xrealloc(zip_dir, zip_dir_size);
+       }
+
+       copy_le32(dirent.magic, 0x02014b50);
+       copy_le16(dirent.creator_version, 0);
+       copy_le16(dirent.version, 20);
+       copy_le16(dirent.flags, 0);
+       copy_le16(dirent.compression_method, method);
+       copy_le16(dirent.mtime, zip_time);
+       copy_le16(dirent.mdate, zip_date);
+       copy_le32(dirent.crc32, crc);
+       copy_le32(dirent.compressed_size, compressed_size);
+       copy_le32(dirent.size, uncompressed_size);
+       copy_le16(dirent.filename_length, pathlen);
+       copy_le16(dirent.extra_length, 0);
+       copy_le16(dirent.comment_length, 0);
+       copy_le16(dirent.disk, 0);
+       copy_le16(dirent.attr1, 0);
+       copy_le32(dirent.attr2, 0);
+       copy_le32(dirent.offset, zip_offset);
+       memcpy(zip_dir + zip_dir_offset, &dirent, sizeof(struct zip_dir_header));
+       zip_dir_offset += sizeof(struct zip_dir_header);
+       memcpy(zip_dir + zip_dir_offset, path, pathlen);
+       zip_dir_offset += pathlen;
+       zip_dir_entries++;
+
+       copy_le32(header.magic, 0x04034b50);
+       copy_le16(header.version, 20);
+       copy_le16(header.flags, 0);
+       copy_le16(header.compression_method, method);
+       copy_le16(header.mtime, zip_time);
+       copy_le16(header.mdate, zip_date);
+       copy_le32(header.crc32, crc);
+       copy_le32(header.compressed_size, compressed_size);
+       copy_le32(header.size, uncompressed_size);
+       copy_le16(header.filename_length, pathlen);
+       copy_le16(header.extra_length, 0);
+       write_or_die(1, &header, sizeof(struct zip_local_header));
+       zip_offset += sizeof(struct zip_local_header);
+       write_or_die(1, path, pathlen);
+       zip_offset += pathlen;
+       if (compressed_size > 0) {
+               write_or_die(1, out, compressed_size);
+               zip_offset += compressed_size;
+       }
+
+out:
+       free(buffer);
+       free(deflated);
+       free(path);
+
+       return result;
+}
+
+static void write_zip_trailer(const unsigned char *sha1)
+{
+       struct zip_dir_trailer trailer;
+
+       copy_le32(trailer.magic, 0x06054b50);
+       copy_le16(trailer.disk, 0);
+       copy_le16(trailer.directory_start_disk, 0);
+       copy_le16(trailer.entries_on_this_disk, zip_dir_entries);
+       copy_le16(trailer.entries, zip_dir_entries);
+       copy_le32(trailer.size, zip_dir_offset);
+       copy_le32(trailer.offset, zip_offset);
+       copy_le16(trailer.comment_length, sha1 ? 40 : 0);
+
+       write_or_die(1, zip_dir, zip_dir_offset);
+       write_or_die(1, &trailer, sizeof(struct zip_dir_trailer));
+       if (sha1)
+               write_or_die(1, sha1_to_hex(sha1), 40);
+}
+
+static void dos_time(time_t *time, int *dos_date, int *dos_time)
+{
+       struct tm *t = localtime(time);
+
+       *dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +
+                   (t->tm_year + 1900 - 1980) * 512;
+       *dos_time = t->tm_sec / 2 + t->tm_min * 32 + t->tm_hour * 2048;
+}
+
+int write_zip_archive(struct archiver_args *args)
+{
+       int plen = strlen(args->base);
+
+       dos_time(&args->time, &zip_date, &zip_time);
+
+       zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
+       zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
+       verbose = args->verbose;
+
+       if (args->base && plen > 0 && args->base[plen - 1] == '/') {
+               char *base = xstrdup(args->base);
+               int baselen = strlen(base);
+
+               while (baselen > 0 && base[baselen - 1] == '/')
+                       base[--baselen] = '\0';
+               write_zip_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
+               free(base);
+       }
+       read_tree_recursive(args->tree, args->base, plen, 0,
+                           args->pathspec, write_zip_entry);
+       write_zip_trailer(args->commit_sha1);
+
+       free(zip_dir);
+
+       return 0;
+}
+
+void *parse_extra_zip_args(int argc, const char **argv)
+{
+       for (; argc > 0; argc--, argv++) {
+               const char *arg = argv[0];
+
+               if (arg[0] == '-' && isdigit(arg[1]) && arg[2] == '\0')
+                       zlib_compression_level = arg[1] - '0';
+               else
+                       die("Unknown argument for zip format: %s", arg);
+       }
+       return NULL;
+}
index 5085018e46d8ebefaf797d62dcc7c9f8f1d06d02..c3ed1ce4929472b4e3fb7577ac61bd914baf0954 100644 (file)
@@ -311,6 +311,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                 */
                sprintf(buf, "%d", shared_repository);
                git_config_set("core.sharedrepository", buf);
+               git_config_set("receive.denyNonFastforwards", "true");
        }
 
        return 0;
index 0c65f9314501bc8c704d326ceeb1ae99bc974b28..b8d7dbc0b71929a95aaebd79d5912897d5eb70e7 100644 (file)
@@ -451,17 +451,6 @@ static int read_one_header_line(char *line, int sz, FILE *in)
        return ofs;
 }
 
-static unsigned hexval(int c)
-{
-       if (c >= '0' && c <= '9')
-               return c - '0';
-       if (c >= 'a' && c <= 'f')
-               return c - 'a' + 10;
-       if (c >= 'A' && c <= 'F')
-               return c - 'A' + 10;
-       return ~0;
-}
-
 static int decode_q_segment(char *in, char *ot, char *ep, int rfc2047)
 {
        int c;
index 0596865679d79e1f02877ea47fb910a7c771f38f..45c92e163c477af4ec7c36c8ee6fcfd9242a0b2d 100644 (file)
@@ -2,13 +2,13 @@
  * Copyright (c) 2006 Franck Bui-Huu
  */
 #include <time.h>
+#include <sys/wait.h>
+#include <sys/poll.h>
 #include "cache.h"
 #include "builtin.h"
 #include "archive.h"
 #include "pkt-line.h"
 #include "sideband.h"
-#include <sys/wait.h>
-#include <sys/poll.h>
 
 static const char upload_archive_usage[] =
        "git-upload-archive <repo>";
diff --git a/builtin-zip-tree.c b/builtin-zip-tree.c
deleted file mode 100644 (file)
index 52d4b7a..0000000
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright (c) 2006 Rene Scharfe
- */
-#include <time.h>
-#include "cache.h"
-#include "commit.h"
-#include "blob.h"
-#include "tree.h"
-#include "quote.h"
-#include "builtin.h"
-#include "archive.h"
-
-static const char zip_tree_usage[] =
-"git-zip-tree [-0|...|-9] <tree-ish> [ <base> ]";
-
-static int verbose;
-static int zip_date;
-static int zip_time;
-
-static unsigned char *zip_dir;
-static unsigned int zip_dir_size;
-
-static unsigned int zip_offset;
-static unsigned int zip_dir_offset;
-static unsigned int zip_dir_entries;
-
-#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
-
-struct zip_local_header {
-       unsigned char magic[4];
-       unsigned char version[2];
-       unsigned char flags[2];
-       unsigned char compression_method[2];
-       unsigned char mtime[2];
-       unsigned char mdate[2];
-       unsigned char crc32[4];
-       unsigned char compressed_size[4];
-       unsigned char size[4];
-       unsigned char filename_length[2];
-       unsigned char extra_length[2];
-};
-
-struct zip_dir_header {
-       unsigned char magic[4];
-       unsigned char creator_version[2];
-       unsigned char version[2];
-       unsigned char flags[2];
-       unsigned char compression_method[2];
-       unsigned char mtime[2];
-       unsigned char mdate[2];
-       unsigned char crc32[4];
-       unsigned char compressed_size[4];
-       unsigned char size[4];
-       unsigned char filename_length[2];
-       unsigned char extra_length[2];
-       unsigned char comment_length[2];
-       unsigned char disk[2];
-       unsigned char attr1[2];
-       unsigned char attr2[4];
-       unsigned char offset[4];
-};
-
-struct zip_dir_trailer {
-       unsigned char magic[4];
-       unsigned char disk[2];
-       unsigned char directory_start_disk[2];
-       unsigned char entries_on_this_disk[2];
-       unsigned char entries[2];
-       unsigned char size[4];
-       unsigned char offset[4];
-       unsigned char comment_length[2];
-};
-
-static void copy_le16(unsigned char *dest, unsigned int n)
-{
-       dest[0] = 0xff & n;
-       dest[1] = 0xff & (n >> 010);
-}
-
-static void copy_le32(unsigned char *dest, unsigned int n)
-{
-       dest[0] = 0xff & n;
-       dest[1] = 0xff & (n >> 010);
-       dest[2] = 0xff & (n >> 020);
-       dest[3] = 0xff & (n >> 030);
-}
-
-static void *zlib_deflate(void *data, unsigned long size,
-                          unsigned long *compressed_size)
-{
-       z_stream stream;
-       unsigned long maxsize;
-       void *buffer;
-       int result;
-
-       memset(&stream, 0, sizeof(stream));
-       deflateInit(&stream, zlib_compression_level);
-       maxsize = deflateBound(&stream, size);
-       buffer = xmalloc(maxsize);
-
-       stream.next_in = data;
-       stream.avail_in = size;
-       stream.next_out = buffer;
-       stream.avail_out = maxsize;
-
-       do {
-               result = deflate(&stream, Z_FINISH);
-       } while (result == Z_OK);
-
-       if (result != Z_STREAM_END) {
-               free(buffer);
-               return NULL;
-       }
-
-       deflateEnd(&stream);
-       *compressed_size = stream.total_out;
-
-       return buffer;
-}
-
-static char *construct_path(const char *base, int baselen,
-                            const char *filename, int isdir, int *pathlen)
-{
-       int filenamelen = strlen(filename);
-       int len = baselen + filenamelen;
-       char *path, *p;
-
-       if (isdir)
-               len++;
-       p = path = xmalloc(len + 1);
-
-       memcpy(p, base, baselen);
-       p += baselen;
-       memcpy(p, filename, filenamelen);
-       p += filenamelen;
-       if (isdir)
-               *p++ = '/';
-       *p = '\0';
-
-       *pathlen = len;
-
-       return path;
-}
-
-static int write_zip_entry(const unsigned char *sha1,
-                           const char *base, int baselen,
-                           const char *filename, unsigned mode, int stage)
-{
-       struct zip_local_header header;
-       struct zip_dir_header dirent;
-       unsigned long compressed_size;
-       unsigned long uncompressed_size;
-       unsigned long crc;
-       unsigned long direntsize;
-       unsigned long size;
-       int method;
-       int result = -1;
-       int pathlen;
-       unsigned char *out;
-       char *path;
-       char type[20];
-       void *buffer = NULL;
-       void *deflated = NULL;
-
-       crc = crc32(0, Z_NULL, 0);
-
-       path = construct_path(base, baselen, filename, S_ISDIR(mode), &pathlen);
-       if (verbose)
-               fprintf(stderr, "%s\n", path);
-       if (pathlen > 0xffff) {
-               error("path too long (%d chars, SHA1: %s): %s", pathlen,
-                     sha1_to_hex(sha1), path);
-               goto out;
-       }
-
-       if (S_ISDIR(mode)) {
-               method = 0;
-               result = READ_TREE_RECURSIVE;
-               out = NULL;
-               uncompressed_size = 0;
-               compressed_size = 0;
-       } else if (S_ISREG(mode)) {
-               method = zlib_compression_level == 0 ? 0 : 8;
-               result = 0;
-               buffer = read_sha1_file(sha1, type, &size);
-               if (!buffer)
-                       die("cannot read %s", sha1_to_hex(sha1));
-               crc = crc32(crc, buffer, size);
-               out = buffer;
-               uncompressed_size = size;
-               compressed_size = size;
-       } else {
-               error("unsupported file mode: 0%o (SHA1: %s)", mode,
-                     sha1_to_hex(sha1));
-               goto out;
-       }
-
-       if (method == 8) {
-               deflated = zlib_deflate(buffer, size, &compressed_size);
-               if (deflated && compressed_size - 6 < size) {
-                       /* ZLIB --> raw compressed data (see RFC 1950) */
-                       /* CMF and FLG ... */
-                       out = (unsigned char *)deflated + 2;
-                       compressed_size -= 6;   /* ... and ADLER32 */
-               } else {
-                       method = 0;
-                       compressed_size = size;
-               }
-       }
-
-       /* make sure we have enough free space in the dictionary */
-       direntsize = sizeof(struct zip_dir_header) + pathlen;
-       while (zip_dir_size < zip_dir_offset + direntsize) {
-               zip_dir_size += ZIP_DIRECTORY_MIN_SIZE;
-               zip_dir = xrealloc(zip_dir, zip_dir_size);
-       }
-
-       copy_le32(dirent.magic, 0x02014b50);
-       copy_le16(dirent.creator_version, 0);
-       copy_le16(dirent.version, 20);
-       copy_le16(dirent.flags, 0);
-       copy_le16(dirent.compression_method, method);
-       copy_le16(dirent.mtime, zip_time);
-       copy_le16(dirent.mdate, zip_date);
-       copy_le32(dirent.crc32, crc);
-       copy_le32(dirent.compressed_size, compressed_size);
-       copy_le32(dirent.size, uncompressed_size);
-       copy_le16(dirent.filename_length, pathlen);
-       copy_le16(dirent.extra_length, 0);
-       copy_le16(dirent.comment_length, 0);
-       copy_le16(dirent.disk, 0);
-       copy_le16(dirent.attr1, 0);
-       copy_le32(dirent.attr2, 0);
-       copy_le32(dirent.offset, zip_offset);
-       memcpy(zip_dir + zip_dir_offset, &dirent, sizeof(struct zip_dir_header));
-       zip_dir_offset += sizeof(struct zip_dir_header);
-       memcpy(zip_dir + zip_dir_offset, path, pathlen);
-       zip_dir_offset += pathlen;
-       zip_dir_entries++;
-
-       copy_le32(header.magic, 0x04034b50);
-       copy_le16(header.version, 20);
-       copy_le16(header.flags, 0);
-       copy_le16(header.compression_method, method);
-       copy_le16(header.mtime, zip_time);
-       copy_le16(header.mdate, zip_date);
-       copy_le32(header.crc32, crc);
-       copy_le32(header.compressed_size, compressed_size);
-       copy_le32(header.size, uncompressed_size);
-       copy_le16(header.filename_length, pathlen);
-       copy_le16(header.extra_length, 0);
-       write_or_die(1, &header, sizeof(struct zip_local_header));
-       zip_offset += sizeof(struct zip_local_header);
-       write_or_die(1, path, pathlen);
-       zip_offset += pathlen;
-       if (compressed_size > 0) {
-               write_or_die(1, out, compressed_size);
-               zip_offset += compressed_size;
-       }
-
-out:
-       free(buffer);
-       free(deflated);
-       free(path);
-
-       return result;
-}
-
-static void write_zip_trailer(const unsigned char *sha1)
-{
-       struct zip_dir_trailer trailer;
-
-       copy_le32(trailer.magic, 0x06054b50);
-       copy_le16(trailer.disk, 0);
-       copy_le16(trailer.directory_start_disk, 0);
-       copy_le16(trailer.entries_on_this_disk, zip_dir_entries);
-       copy_le16(trailer.entries, zip_dir_entries);
-       copy_le32(trailer.size, zip_dir_offset);
-       copy_le32(trailer.offset, zip_offset);
-       copy_le16(trailer.comment_length, sha1 ? 40 : 0);
-
-       write_or_die(1, zip_dir, zip_dir_offset);
-       write_or_die(1, &trailer, sizeof(struct zip_dir_trailer));
-       if (sha1)
-               write_or_die(1, sha1_to_hex(sha1), 40);
-}
-
-static void dos_time(time_t *time, int *dos_date, int *dos_time)
-{
-       struct tm *t = localtime(time);
-
-       *dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +
-                   (t->tm_year + 1900 - 1980) * 512;
-       *dos_time = t->tm_sec / 2 + t->tm_min * 32 + t->tm_hour * 2048;
-}
-
-int cmd_zip_tree(int argc, const char **argv, const char *prefix)
-{
-       unsigned char sha1[20];
-       struct tree *tree;
-       struct commit *commit;
-       time_t archive_time;
-       char *base;
-       int baselen;
-
-       git_config(git_default_config);
-
-       if (argc > 1 && argv[1][0] == '-') {
-               if (isdigit(argv[1][1]) && argv[1][2] == '\0') {
-                       zlib_compression_level = argv[1][1] - '0';
-                       argc--;
-                       argv++;
-               }
-       }
-
-       switch (argc) {
-       case 3:
-               base = xstrdup(argv[2]);
-               baselen = strlen(base);
-               break;
-       case 2:
-               base = xstrdup("");
-               baselen = 0;
-               break;
-       default:
-               usage(zip_tree_usage);
-       }
-
-       if (get_sha1(argv[1], sha1))
-               die("Not a valid object name %s", argv[1]);
-
-       commit = lookup_commit_reference_gently(sha1, 1);
-       archive_time = commit ? commit->date : time(NULL);
-       dos_time(&archive_time, &zip_date, &zip_time);
-
-       zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
-       zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
-
-       tree = parse_tree_indirect(sha1);
-       if (!tree)
-               die("not a tree object");
-
-       if (baselen > 0) {
-               write_zip_entry(tree->object.sha1, "", 0, base, 040777, 0);
-               base = xrealloc(base, baselen + 1);
-               base[baselen] = '/';
-               baselen++;
-               base[baselen] = '\0';
-       }
-       read_tree_recursive(tree, base, baselen, 0, NULL, write_zip_entry);
-       write_zip_trailer(commit ? commit->object.sha1 : NULL);
-
-       free(zip_dir);
-       free(base);
-
-       return 0;
-}
-
-int write_zip_archive(struct archiver_args *args)
-{
-       int plen = strlen(args->base);
-
-       dos_time(&args->time, &zip_date, &zip_time);
-
-       zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
-       zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
-       verbose = args->verbose;
-
-       if (args->base && plen > 0 && args->base[plen - 1] == '/') {
-               char *base = xstrdup(args->base);
-               int baselen = strlen(base);
-
-               while (baselen > 0 && base[baselen - 1] == '/')
-                       base[--baselen] = '\0';
-               write_zip_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
-               free(base);
-       }
-       read_tree_recursive(args->tree, args->base, plen, 0,
-                           args->pathspec, write_zip_entry);
-       write_zip_trailer(args->commit_sha1);
-
-       free(zip_dir);
-
-       return 0;
-}
-
-void *parse_extra_zip_args(int argc, const char **argv)
-{
-       for (; argc > 0; argc--, argv++) {
-               const char *arg = argv[0];
-
-               if (arg[0] == '-' && isdigit(arg[1]) && arg[2] == '\0')
-                       zlib_compression_level = arg[1] - '0';
-               else
-                       die("Unknown argument for zip format: %s", arg);
-       }
-       return NULL;
-}
index ccade94e26b34f9005b1ed2575b4c11cb6ceab22..f9fa9ff1d245e81630438d2b321cfe04c7905905 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -53,7 +53,6 @@ extern int cmd_show(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
 extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
-extern int cmd_zip_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_update_index(int argc, const char **argv, const char *prefix);
 extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
diff --git a/cache.h b/cache.h
index 57db7c9b20aad5d14ab4e77fd0e338b98c446bcc..ef2e58147535c455c5be2b014af9945fb41c35d0 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -188,6 +188,7 @@ extern int prefer_symlink_refs;
 extern int log_all_ref_updates;
 extern int warn_ambiguous_refs;
 extern int shared_repository;
+extern int deny_non_fast_forwards;
 extern const char *apply_default_whitespace;
 extern int zlib_compression_level;
 
@@ -278,6 +279,12 @@ enum object_type {
        OBJ_BAD,
 };
 
+extern signed char hexval_table[256];
+static inline unsigned int hexval(unsigned int c)
+{
+       return hexval_table[c];
+}
+
 /* Convert to/from hex/sha1 representation */
 #define MINIMUM_ABBREV 4
 #define DEFAULT_ABBREV 7
index 84d870ca4eca6e202bcbec388e9a299b887f9a12..63b1d155be1aca2f9fe7aad5f747c06b9102fd60 100644 (file)
@@ -20,6 +20,7 @@ int warn_ambiguous_refs = 1;
 int repository_format_version;
 char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
 int shared_repository = PERM_UMASK;
+int deny_non_fast_forwards = 0;
 const char *apply_default_whitespace;
 int zlib_compression_level = Z_DEFAULT_COMPRESSION;
 int pager_in_use;
index a7bc680d90cb503c50d25b15bcaba662c5f5b49e..729ec65dc9e0ddebfe81fb4d837a5f9c83b537ee 100755 (executable)
@@ -5,6 +5,10 @@
 # Resolve two trees.
 #
 
+echo 'WARNING: This command is DEPRECATED and will be removed very soon.' >&2
+echo 'WARNING: Please use git-merge or git-pull instead.' >&2
+sleep 2
+
 USAGE='<head> <remote> <merge-message>'
 . git-sh-setup
 
diff --git a/git.c b/git.c
index 44ab0de94d84e3b09d753b1da85679efcfd793a0..1686220488bb62dbf2e238dc488d3fb739156fae 100644 (file)
--- a/git.c
+++ b/git.c
@@ -259,7 +259,6 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "stripspace", cmd_stripspace },
                { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
                { "tar-tree", cmd_tar_tree, RUN_SETUP },
-               { "zip-tree", cmd_zip_tree, RUN_SETUP },
                { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
                { "update-index", cmd_update_index, RUN_SETUP },
                { "update-ref", cmd_update_ref, RUN_SETUP },
index baadbe751275ccd0205af089d9ab4b245fa6a62c..0693a833c173ab9218ea791b7678d399129a83cf 100755 (executable)
@@ -212,19 +212,9 @@ sub feature_pickaxe {
        }
 }
 
+# We have to handle those containing any characters:
 our $file_name = $cgi->param('f');
-if (defined $file_name) {
-       if (!validate_input($file_name)) {
-               die_error(undef, "Invalid file parameter");
-       }
-}
-
 our $file_parent = $cgi->param('fp');
-if (defined $file_parent) {
-       if (!validate_input($file_parent)) {
-               die_error(undef, "Invalid file parent parameter");
-       }
-}
 
 our $hash = $cgi->param('h');
 if (defined $hash) {
@@ -300,11 +290,12 @@ sub evaluate_path_info {
                $pathname =~ s,^/+,,;
                if (!$pathname || substr($pathname, -1) eq "/") {
                        $action  ||= "tree";
+                       $pathname =~ s,/$,,;
                } else {
                        $action  ||= "blob_plain";
                }
                $hash_base ||= validate_input($refname);
-               $file_name ||= validate_input($pathname);
+               $file_name ||= $pathname;
        } elsif (defined $refname) {
                # we got "project.git/branch"
                $action ||= "shortlog";
@@ -415,7 +406,7 @@ sub validate_input {
 # correct, but quoted slashes look too horrible in bookmarks
 sub esc_param {
        my $str = shift;
-       $str =~ s/([^A-Za-z0-9\-_.~();\/;?:@&=])/sprintf("%%%02X", ord($1))/eg;
+       $str =~ s/([^A-Za-z0-9\-_.~()\/:@])/sprintf("%%%02X", ord($1))/eg;
        $str =~ s/\+/%2B/g;
        $str =~ s/ /\+/g;
        return $str;
@@ -717,6 +708,7 @@ sub git_get_project_config {
 sub git_get_hash_by_path {
        my $base = shift;
        my $path = shift || return undef;
+       my $type = shift;
 
        my $tree = $base;
 
@@ -727,6 +719,10 @@ sub git_get_hash_by_path {
 
        #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa  panic.c'
        $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
+       if (defined $type && $type ne $2) {
+               # type doesn't match
+               return undef;
+       }
        return $3;
 }
 
@@ -746,7 +742,7 @@ sub git_get_project_description {
 sub git_get_project_url_list {
        my $path = shift;
 
-       open my $fd, "$projectroot/$path/cloneurl" or return undef;
+       open my $fd, "$projectroot/$path/cloneurl" or return;
        my @git_project_url_list = map { chomp; $_ } <$fd>;
        close $fd;
 
@@ -1276,7 +1272,7 @@ sub git_header_html {
                if (defined $action) {
                        $title .= "/$action";
                        if (defined $file_name) {
-                               $title .= " - $file_name";
+                               $title .= " - " . esc_html($file_name);
                                if ($action eq "tree" && $file_name !~ m|/$|) {
                                        $title .= "/";
                                }
@@ -1513,12 +1509,15 @@ sub git_print_page_path {
                my $fullname = '';
 
                print "<div class=\"page_path\">";
+               print $cgi->a({-href => href(action=>"tree", hash_base=>$hb),
+                             -title => 'tree root'}, "[$project]");
+               print " / ";
                foreach my $dir (@dirname) {
-                       $fullname .= $dir . '/';
+                       $fullname .= ($fullname ? '/' : '') . $dir;
                        print $cgi->a({-href => href(action=>"tree", file_name=>$fullname,
                                                     hash_base=>$hb),
                                      -title => $fullname}, esc_html($dir));
-                       print "/";
+                       print " / ";
                }
                if (defined $type && $type eq 'blob') {
                        print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
@@ -1528,7 +1527,6 @@ sub git_print_page_path {
                        print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
                                                     hash_base=>$hb),
                                      -title => $name}, esc_html($basename));
-                       print "/";
                } else {
                        print esc_html($basename);
                }
@@ -1967,9 +1965,6 @@ sub git_shortlog_body {
        # uses global variable $project
        my ($revlist, $from, $to, $refs, $extra) = @_;
 
-       my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
-       my $have_snapshot = (defined $ctype && defined $suffix);
-
        $from = 0 unless defined $from;
        $to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
 
@@ -1995,10 +1990,8 @@ sub git_shortlog_body {
                print "</td>\n" .
                      "<td class=\"link\">" .
                      $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
-                     $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff");
-               if ($have_snapshot) {
-                       print " | " .  $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
-               }
+                     $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " .
+                     $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree");
                print "</td>\n" .
                      "</tr>\n";
        }
@@ -2160,7 +2153,8 @@ sub git_heads_body {
                      "</td>\n" .
                      "<td class=\"link\">" .
                      $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . " | " .
-                     $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") .
+                     $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") . " | " .
+                     $cgi->a({-href => href(action=>"tree", hash=>$tag{'name'}, hash_base=>$tag{'name'})}, "tree") .
                      "</td>\n" .
                      "</tr>";
        }
@@ -2274,7 +2268,8 @@ sub git_project_list {
                      "<td class=\"link\">" .
                      $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary")}, "summary")   . " | " .
                      $cgi->a({-href => href(project=>$pr->{'path'}, action=>"shortlog")}, "shortlog") . " | " .
-                     $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") .
+                     $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . " | " .
+                     $cgi->a({-href => href(project=>$pr->{'path'}, action=>"tree")}, "tree") .
                      "</td>\n" .
                      "</tr>\n";
        }
@@ -2425,15 +2420,18 @@ sub git_blame2 {
        if ($ftype !~ "blob") {
                die_error("400 Bad Request", "Object is not a blob");
        }
-       open ($fd, "-|", git_cmd(), "blame", '-l', $file_name, $hash_base)
+       open ($fd, "-|", git_cmd(), "blame", '-l', '--', $file_name, $hash_base)
                or die_error(undef, "Open git-blame failed");
        git_header_html();
        my $formats_nav =
                $cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)},
                        "blob") .
                " | " .
+               $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)},
+                       "history") .
+               " | " .
                $cgi->a({-href => href(action=>"blame", file_name=>$file_name)},
-                       "head");
+                       "HEAD");
        git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
        git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
        git_print_page_path($file_name, $ftype, $hash_base);
@@ -2498,8 +2496,11 @@ sub git_blame {
                $cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)},
                        "blob") .
                " | " .
+               $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)},
+                       "history") .
+               " | " .
                $cgi->a({-href => href(action=>"blame", file_name=>$file_name)},
-                       "head");
+                       "HEAD");
        git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
        git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
        git_print_page_path($file_name, 'blob', $hash_base);
@@ -2673,16 +2674,20 @@ sub git_blob {
                                        " | ";
                        }
                        $formats_nav .=
+                               $cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
+                                                      hash=>$hash, file_name=>$file_name)},
+                                       "history") .
+                               " | " .
                                $cgi->a({-href => href(action=>"blob_plain",
                                                       hash=>$hash, file_name=>$file_name)},
-                                       "plain") .
+                                       "raw") .
                                " | " .
                                $cgi->a({-href => href(action=>"blob",
                                                       hash_base=>"HEAD", file_name=>$file_name)},
-                                       "head");
+                                       "HEAD");
                } else {
                        $formats_nav .=
-                               $cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "plain");
+                               $cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "raw");
                }
                git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
                git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
@@ -2708,6 +2713,9 @@ sub git_blob {
 }
 
 sub git_tree {
+       my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+       my $have_snapshot = (defined $ctype && defined $suffix);
+
        if (!defined $hash) {
                $hash = git_get_head_hash($project);
                if (defined $file_name) {
@@ -2731,7 +2739,23 @@ sub git_tree {
        my $base = "";
        my ($have_blame) = gitweb_check_feature('blame');
        if (defined $hash_base && (my %co = parse_commit($hash_base))) {
-               git_print_page_nav('tree','', $hash_base);
+               my @views_nav = ();
+               if (defined $file_name) {
+                       push @views_nav,
+                               $cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
+                                                      hash=>$hash, file_name=>$file_name)},
+                                       "history"),
+                               $cgi->a({-href => href(action=>"tree",
+                                                      hash_base=>"HEAD", file_name=>$file_name)},
+                                       "HEAD"),
+               }
+               if ($have_snapshot) {
+                       # FIXME: Should be available when we have no hash base as well.
+                       push @views_nav,
+                               $cgi->a({-href => href(action=>"snapshot", hash=>$hash)},
+                                       "snapshot");
+               }
+               git_print_page_nav('tree','', $hash_base, undef, undef, join(' | ', @views_nav));
                git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
        } else {
                undef $hash_base;
@@ -2836,6 +2860,8 @@ sub git_log {
                      $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") .
                      " | " .
                      $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") .
+                     " | " .
+                     $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") .
                      "<br/>\n" .
                      "</div>\n" .
                      "<i>" . esc_html($co{'author_name'}) .  " [$ad{'rfc2822'}]</i><br/>\n" .
@@ -2876,17 +2902,22 @@ sub git_commit {
        my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
        my $have_snapshot = (defined $ctype && defined $suffix);
 
-       my $formats_nav = '';
+       my @views_nav = ();
        if (defined $file_name && defined $co{'parent'}) {
                my $parent = $co{'parent'};
-               $formats_nav .=
+               push @views_nav,
                        $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)},
                                "blame");
        }
+       if (defined $co{'parent'}) {
+               push @views_nav,
+                       $cgi->a({-href => href(action=>"shortlog", hash=>$hash)}, "shortlog"),
+                       $cgi->a({-href => href(action=>"log", hash=>$hash)}, "log");
+       }
        git_header_html(undef, $expires);
        git_print_page_nav('commit', defined $co{'parent'} ? '' : 'commitdiff',
                           $hash, $co{'tree'}, $hash,
-                          $formats_nav);
+                          join (' | ', @views_nav));
 
        if (defined $co{'parent'}) {
                git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
@@ -3031,12 +3062,12 @@ sub git_blobdiff {
                if (defined $file_name) {
                        if (defined $file_parent) {
                                $diffinfo{'status'} = '2';
-                               $diffinfo{'from_file'} = $file_parent;
-                               $diffinfo{'to_file'}   = $file_name;
+                               $diffinfo{'from_file'} = esc_html($file_parent);
+                               $diffinfo{'to_file'}   = esc_html($file_name);
                        } else { # assume not renamed
                                $diffinfo{'status'} = '1';
-                               $diffinfo{'from_file'} = $file_name;
-                               $diffinfo{'to_file'}   = $file_name;
+                               $diffinfo{'from_file'} = esc_html($file_name);
+                               $diffinfo{'to_file'}   = esc_html($file_name);
                        }
                } else { # no filename given
                        $diffinfo{'status'} = '2';
@@ -3065,7 +3096,7 @@ sub git_blobdiff {
                                               hash=>$hash, hash_parent=>$hash_parent,
                                               hash_base=>$hash_base, hash_parent_base=>$hash_parent_base,
                                               file_name=>$file_name, file_parent=>$file_parent)},
-                               "plain");
+                               "raw");
                git_header_html(undef, $expires);
                if (defined $hash_base && (my %co = parse_commit($hash_base))) {
                        git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
@@ -3085,7 +3116,7 @@ sub git_blobdiff {
                        -type => 'text/plain',
                        -charset => 'utf-8',
                        -expires => $expires,
-                       -content_disposition => qq(inline; filename="${file_name}.patch"));
+                       -content_disposition => qq(inline; filename=") . quotemeta($file_name) . qq(.patch"));
 
                print "X-Git-Url: " . $cgi->self_url() . "\n\n";
 
@@ -3168,7 +3199,7 @@ sub git_commitdiff {
                my $formats_nav =
                        $cgi->a({-href => href(action=>"commitdiff_plain",
                                               hash=>$hash, hash_parent=>$hash_parent)},
-                               "plain");
+                               "raw");
 
                git_header_html(undef, $expires);
                git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
@@ -3535,7 +3566,7 @@ sub git_rss {
                        if (!($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/)) {
                                next;
                        }
-                       my $file = validate_input(unquote($7));
+                       my $file = esc_html(unquote($7));
                        $file = decode("utf8", $file, Encode::FB_DEFAULT);
                        print "$file<br/>\n";
                }
index 78f75da5ca99bd5457fd4e0f6e3af2737afc335a..ea2dbd4e3398ca90823dcd453cbb52c5dcea135c 100644 (file)
@@ -2,6 +2,8 @@
 #include "refs.h"
 #include "pkt-line.h"
 #include "run-command.h"
+#include "commit.h"
+#include "object.h"
 
 static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
 
@@ -127,6 +129,21 @@ static int update(struct command *cmd)
                return error("unpack should have generated %s, "
                             "but I can't find it!", new_hex);
        }
+       if (deny_non_fast_forwards && !is_null_sha1(old_sha1)) {
+               struct commit *old_commit, *new_commit;
+               struct commit_list *bases, *ent;
+
+               old_commit = (struct commit *)parse_object(old_sha1);
+               new_commit = (struct commit *)parse_object(new_sha1);
+               bases = get_merge_bases(old_commit, new_commit, 1);
+               for (ent = bases; ent; ent = ent->next)
+                       if (!hashcmp(old_sha1, ent->item->object.sha1))
+                               break;
+               free_commit_list(bases);
+               if (!ent)
+                       return error("denying non-fast forward;"
+                                    " you should pull first");
+       }
        safe_create_leading_directories(lock_name);
 
        newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
diff --git a/setup.c b/setup.c
index 2afdba414a073705440f887593a1b5daa1023758..9a46a58a4a34a345eb9f9b623a255c9bcba4c757 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -244,6 +244,8 @@ int check_repository_format_version(const char *var, const char *value)
                repository_format_version = git_config_int(var, value);
        else if (strcmp(var, "core.sharedrepository") == 0)
                shared_repository = git_config_perm(var, value);
+       else if (strcmp(var, "receive.denynonfastforwards") == 0)
+               deny_non_fast_forwards = git_config_bool(var, value);
        return 0;
 }
 
index b89edb9515aa38c2c404367aa28ec5531fcc7de1..0f9c2b62187ae35b07d0d678ac233e2c7125c428 100644 (file)
@@ -26,44 +26,40 @@ const unsigned char null_sha1[20];
 
 static unsigned int sha1_file_open_flag = O_NOATIME;
 
-static inline unsigned int hexval(unsigned int c)
-{
-       static signed char val[256] = {
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 00-07 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 08-0f */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 10-17 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 18-1f */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 20-27 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 28-2f */
-                 0,  1,  2,  3,  4,  5,  6,  7,                /* 30-37 */
-                 8,  9, -1, -1, -1, -1, -1, -1,                /* 38-3f */
-                -1, 10, 11, 12, 13, 14, 15, -1,                /* 40-47 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 48-4f */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 50-57 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 58-5f */
-                -1, 10, 11, 12, 13, 14, 15, -1,                /* 60-67 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 68-67 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 70-77 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 78-7f */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 80-87 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 88-8f */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 90-97 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* 98-9f */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* a0-a7 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* a8-af */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* b0-b7 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* b8-bf */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* c0-c7 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* c8-cf */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* d0-d7 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* d8-df */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* e0-e7 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* e8-ef */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* f0-f7 */
-                -1, -1, -1, -1, -1, -1, -1, -1,                /* f8-ff */
-       };
-       return val[c];
-}
+signed char hexval_table[256] = {
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 00-07 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 08-0f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 10-17 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 18-1f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 20-27 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 28-2f */
+         0,  1,  2,  3,  4,  5,  6,  7,                /* 30-37 */
+         8,  9, -1, -1, -1, -1, -1, -1,                /* 38-3f */
+        -1, 10, 11, 12, 13, 14, 15, -1,                /* 40-47 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 48-4f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 50-57 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 58-5f */
+        -1, 10, 11, 12, 13, 14, 15, -1,                /* 60-67 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 68-67 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 70-77 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 78-7f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 80-87 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 88-8f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 90-97 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 98-9f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* a0-a7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* a8-af */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* b0-b7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* b8-bf */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* c0-c7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* c8-cf */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* d0-d7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* d8-df */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* e0-e7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* e8-ef */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* f0-f7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* f8-ff */
+};
 
 int get_sha1_hex(const char *hex, unsigned char *sha1)
 {
index 1fbc4438059b68f31aa25fb8e3b82b37a4d02819..9b226e3579b68fe8b59c7105bd926e3a0a70b0ad 100644 (file)
@@ -431,6 +431,26 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
        return 0;
 }
 
+static int get_describe_name(const char *name, int len, unsigned char *sha1)
+{
+       const char *cp;
+
+       for (cp = name + len - 1; name + 2 <= cp; cp--) {
+               char ch = *cp;
+               if (hexval(ch) & ~0377) {
+                       /* We must be looking at g in "SOMETHING-g"
+                        * for it to be describe output.
+                        */
+                       if (ch == 'g' && cp[-1] == '-') {
+                               cp++;
+                               len -= cp - name;
+                               return get_short_sha1(cp, len, sha1, 1);
+                       }
+               }
+       }
+       return -1;
+}
+
 static int get_sha1_1(const char *name, int len, unsigned char *sha1)
 {
        int ret, has_suffix;
@@ -472,6 +492,12 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)
        ret = get_sha1_basic(name, len, sha1);
        if (!ret)
                return 0;
+
+       /* It could be describe output that is "SOMETHING-gXXXX" */
+       ret = get_describe_name(name, len, sha1);
+       if (!ret)
+               return 0;
+
        return get_short_sha1(name, len, sha1, 0);
 }
 
index f3694ac3c78e64b6b77ebfef4cb3e90f9fb6c32c..8afb89971752fe4a91b9b7c62b4b0a6b69a8272b 100755 (executable)
@@ -64,4 +64,18 @@ test_expect_success \
        cmp victim/.git/refs/heads/master .git/refs/heads/master
 '
 
+unset GIT_CONFIG GIT_CONFIG_LOCAL
+HOME=`pwd`/no-such-directory
+export HOME ;# this way we force the victim/.git/config to be used.
+
+test_expect_success \
+        'pushing with --force should be denied with denyNonFastforwards' '
+       cd victim &&
+       git-repo-config receive.denyNonFastforwards true &&
+       cd .. &&
+       git-update-ref refs/heads/master master^ &&
+       git-send-pack --force ./victim/.git/ master &&
+       ! diff -u .git/refs/heads/master victim/.git/refs/heads/master
+'
+
 test_done
index e2629339d4b1c9acf8cdf002f8ac59ef736eacf3..e75ad5faace6e40e7f6f3f47e9be90b0e9c4691e 100755 (executable)
@@ -34,7 +34,7 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
 export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
 export EDITOR VISUAL
 
-case $(echo $GIT_TRACE |tr [A-Z] [a-z]) in
+case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
        1|2|true)
                echo "* warning: Some tests will not work if GIT_TRACE" \
                        "is set as to trace on STDERR ! *"