pack-objects: don't leak pack window reference when splitting packs
[gitweb.git] / builtin-receive-pack.c
index 6d6027ead17b86519d69c3dfc9b98c01e916d277..2c0225c89a44a28150806608ea3956c44e27ef6f 100644 (file)
@@ -6,9 +6,12 @@
 #include "exec_cmd.h"
 #include "commit.h"
 #include "object.h"
+#include "remote.h"
+#include "transport.h"
 
 static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
 
+static int deny_deletes = 0;
 static int deny_non_fast_forwards = 0;
 static int receive_fsck_objects;
 static int receive_unpack_limit = -1;
@@ -21,6 +24,11 @@ static int capabilities_sent;
 
 static int receive_pack_config(const char *var, const char *value, void *cb)
 {
+       if (strcmp(var, "receive.denydeletes") == 0) {
+               deny_deletes = git_config_bool(var, value);
+               return 0;
+       }
+
        if (strcmp(var, "receive.denynonfastforwards") == 0) {
                deny_non_fast_forwards = git_config_bool(var, value);
                return 0;
@@ -183,6 +191,12 @@ static const char *update(struct command *cmd)
                      "but I can't find it!", sha1_to_hex(new_sha1));
                return "bad pack";
        }
+       if (deny_deletes && is_null_sha1(new_sha1) &&
+           !is_null_sha1(old_sha1) &&
+           !prefixcmp(name, "refs/heads/")) {
+               error("denying ref deletion for %s", name);
+               return "deletion prohibited";
+       }
        if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
            !is_null_sha1(old_sha1) &&
            !prefixcmp(name, "refs/heads/")) {
@@ -462,6 +476,45 @@ static int delete_only(struct command *cmd)
        return 1;
 }
 
+static int add_refs_from_alternate(struct alternate_object_database *e, void *unused)
+{
+       char *other;
+       size_t len;
+       struct remote *remote;
+       struct transport *transport;
+       const struct ref *extra;
+
+       e->name[-1] = '\0';
+       other = xstrdup(make_absolute_path(e->base));
+       e->name[-1] = '/';
+       len = strlen(other);
+
+       while (other[len-1] == '/')
+               other[--len] = '\0';
+       if (len < 8 || memcmp(other + len - 8, "/objects", 8))
+               return 0;
+       /* Is this a git repository with refs? */
+       memcpy(other + len - 8, "/refs", 6);
+       if (!is_directory(other))
+               return 0;
+       other[len - 8] = '\0';
+       remote = remote_get(other);
+       transport = transport_get(remote, other);
+       for (extra = transport_get_remote_refs(transport);
+            extra;
+            extra = extra->next) {
+               add_extra_ref(".have", extra->old_sha1, 0);
+       }
+       transport_disconnect(transport);
+       free(other);
+       return 0;
+}
+
+static void add_alternate_refs(void)
+{
+       foreach_alt_odb(add_refs_from_alternate, NULL);
+}
+
 int cmd_receive_pack(int argc, const char **argv, const char *prefix)
 {
        int i;
@@ -497,7 +550,9 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
        else if (0 <= receive_unpack_limit)
                unpack_limit = receive_unpack_limit;
 
+       add_alternate_refs();
        write_head_info();
+       clear_extra_refs();
 
        /* EOF */
        packet_flush(1);