Merge branch 'jk/tighten-alloc'
authorJunio C Hamano <gitster@pobox.com>
Wed, 17 Aug 2016 21:07:46 +0000 (14:07 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 17 Aug 2016 21:07:46 +0000 (14:07 -0700)
Small code and comment clean-up.

* jk/tighten-alloc:
receive-pack: use FLEX_ALLOC_MEM in queue_command()
correct FLEXPTR_* example in comment

1  2 
builtin/receive-pack.c
git-compat-util.h
diff --combined builtin/receive-pack.c
index 92e1213ecc05969f4601c7d3c48f6d96dcf72a0a,b55d0aaee71980bf90d884f4b58ca11d8004e818..011db00d31709408a21b97abfb5742b97b54238d
  #include "sigchain.h"
  #include "fsck.h"
  
 -static const char receive_pack_usage[] = "git receive-pack <git-dir>";
 +static const char * const receive_pack_usage[] = {
 +      N_("git receive-pack <git-dir>"),
 +      NULL
 +};
  
  enum deny_action {
        DENY_UNCONFIGURED,
@@@ -44,17 -41,15 +44,17 @@@ static struct strbuf fsck_msg_types = S
  static int receive_unpack_limit = -1;
  static int transfer_unpack_limit = -1;
  static int advertise_atomic_push = 1;
 +static int advertise_push_options;
  static int unpack_limit = 100;
  static int report_status;
  static int use_sideband;
  static int use_atomic;
 +static int use_push_options;
  static int quiet;
  static int prefer_ofs_delta = 1;
  static int auto_update_server_info;
  static int auto_gc = 1;
 -static int fix_thin = 1;
 +static int reject_thin;
  static int stateless_rpc;
  static const char *service_dir;
  static const char *head_name;
@@@ -78,13 -73,6 +78,13 @@@ static long nonce_stamp_slop
  static unsigned long nonce_stamp_slop_limit;
  static struct ref_transaction *transaction;
  
 +static enum {
 +      KEEPALIVE_NEVER = 0,
 +      KEEPALIVE_AFTER_NUL,
 +      KEEPALIVE_ALWAYS
 +} use_keepalive;
 +static int keepalive_in_sec = 5;
 +
  static enum deny_action parse_deny_action(const char *var, const char *value)
  {
        if (value) {
@@@ -202,16 -190,6 +202,16 @@@ static int receive_pack_config(const ch
                return 0;
        }
  
 +      if (strcmp(var, "receive.advertisepushoptions") == 0) {
 +              advertise_push_options = git_config_bool(var, value);
 +              return 0;
 +      }
 +
 +      if (strcmp(var, "receive.keepalive") == 0) {
 +              keepalive_in_sec = git_config_int(var, value);
 +              return 0;
 +      }
 +
        return git_default_config(var, value, cb);
  }
  
@@@ -230,8 -208,6 +230,8 @@@ static void show_ref(const char *path, 
                        strbuf_addstr(&cap, " ofs-delta");
                if (push_cert_nonce)
                        strbuf_addf(&cap, " push-cert=%s", push_cert_nonce);
 +              if (advertise_push_options)
 +                      strbuf_addstr(&cap, " push-options");
                strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
                packet_write(1, "%s %s%c%s\n",
                             sha1_to_hex(sha1), path, 0, cap.buf);
@@@ -340,60 -316,10 +340,60 @@@ static void rp_error(const char *err, .
  static int copy_to_sideband(int in, int out, void *arg)
  {
        char data[128];
 +      int keepalive_active = 0;
 +
 +      if (keepalive_in_sec <= 0)
 +              use_keepalive = KEEPALIVE_NEVER;
 +      if (use_keepalive == KEEPALIVE_ALWAYS)
 +              keepalive_active = 1;
 +
        while (1) {
 -              ssize_t sz = xread(in, data, sizeof(data));
 +              ssize_t sz;
 +
 +              if (keepalive_active) {
 +                      struct pollfd pfd;
 +                      int ret;
 +
 +                      pfd.fd = in;
 +                      pfd.events = POLLIN;
 +                      ret = poll(&pfd, 1, 1000 * keepalive_in_sec);
 +
 +                      if (ret < 0) {
 +                              if (errno == EINTR)
 +                                      continue;
 +                              else
 +                                      break;
 +                      } else if (ret == 0) {
 +                              /* no data; send a keepalive packet */
 +                              static const char buf[] = "0005\1";
 +                              write_or_die(1, buf, sizeof(buf) - 1);
 +                              continue;
 +                      } /* else there is actual data to read */
 +              }
 +
 +              sz = xread(in, data, sizeof(data));
                if (sz <= 0)
                        break;
 +
 +              if (use_keepalive == KEEPALIVE_AFTER_NUL && !keepalive_active) {
 +                      const char *p = memchr(data, '\0', sz);
 +                      if (p) {
 +                              /*
 +                               * The NUL tells us to start sending keepalives. Make
 +                               * sure we send any other data we read along
 +                               * with it.
 +                               */
 +                              keepalive_active = 1;
 +                              send_sideband(1, 2, data, p - data, use_sideband);
 +                              send_sideband(1, 2, p + 1, sz - (p - data + 1), use_sideband);
 +                              continue;
 +                      }
 +              }
 +
 +              /*
 +               * Either we're not looking for a NUL signal, or we didn't see
 +               * it yet; just pass along the data.
 +               */
                send_sideband(1, 2, data, sz, use_sideband);
        }
        close(in);
@@@ -621,16 -547,8 +621,16 @@@ static void prepare_push_cert_sha1(stru
        }
  }
  
 +struct receive_hook_feed_state {
 +      struct command *cmd;
 +      int skip_broken;
 +      struct strbuf buf;
 +      const struct string_list *push_options;
 +};
 +
  typedef int (*feed_fn)(void *, const char **, size_t *);
 -static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_state)
 +static int run_and_feed_hook(const char *hook_name, feed_fn feed,
 +                           struct receive_hook_feed_state *feed_state)
  {
        struct child_process proc = CHILD_PROCESS_INIT;
        struct async muxer;
        proc.argv = argv;
        proc.in = -1;
        proc.stdout_to_stderr = 1;
 +      if (feed_state->push_options) {
 +              int i;
 +              for (i = 0; i < feed_state->push_options->nr; i++)
 +                      argv_array_pushf(&proc.env_array,
 +                              "GIT_PUSH_OPTION_%d=%s", i,
 +                              feed_state->push_options->items[i].string);
 +              argv_array_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT=%d",
 +                               feed_state->push_options->nr);
 +      } else
 +              argv_array_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT");
  
        if (use_sideband) {
                memset(&muxer, 0, sizeof(muxer));
        return finish_command(&proc);
  }
  
 -struct receive_hook_feed_state {
 -      struct command *cmd;
 -      int skip_broken;
 -      struct strbuf buf;
 -};
 -
  static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
  {
        struct receive_hook_feed_state *state = state_;
        return 0;
  }
  
 -static int run_receive_hook(struct command *commands, const char *hook_name,
 -                          int skip_broken)
 +static int run_receive_hook(struct command *commands,
 +                          const char *hook_name,
 +                          int skip_broken,
 +                          const struct string_list *push_options)
  {
        struct receive_hook_feed_state state;
        int status;
        if (feed_receive_hook(&state, NULL, NULL))
                return 0;
        state.cmd = commands;
 +      state.push_options = push_options;
        status = run_and_feed_hook(hook_name, feed_receive_hook, &state);
        strbuf_release(&state.buf);
        return status;
@@@ -823,7 -734,7 +823,7 @@@ static int update_shallow_ref(struct co
  {
        static struct lock_file shallow_lock;
        struct sha1_array extra = SHA1_ARRAY_INIT;
 -      const char *alt_file;
 +      struct check_connected_options opt = CHECK_CONNECTED_INIT;
        uint32_t mask = 1 << (cmd->index % 32);
        int i;
  
                    !delayed_reachability_test(si, i))
                        sha1_array_append(&extra, si->shallow->sha1[i]);
  
 -      setup_alternate_shallow(&shallow_lock, &alt_file, &extra);
 -      if (check_shallow_connected(command_singleton_iterator,
 -                                  0, cmd, alt_file)) {
 +      setup_alternate_shallow(&shallow_lock, &opt.shallow_file, &extra);
 +      if (check_connected(command_singleton_iterator, cmd, &opt)) {
                rollback_lock_file(&shallow_lock);
                sha1_array_clear(&extra);
                return -1;
@@@ -1169,13 -1081,13 +1169,13 @@@ static void check_aliased_update(struc
        if (!(flag & REF_ISSYMREF))
                return;
  
 -      dst_name = strip_namespace(dst_name);
        if (!dst_name) {
                rp_error("refusing update to broken symref '%s'", cmd->ref_name);
                cmd->skip_update = 1;
                cmd->error_string = "broken symref";
                return;
        }
 +      dst_name = strip_namespace(dst_name);
  
        if ((item = string_list_lookup(list, dst_name)) == NULL)
                return;
@@@ -1245,8 -1157,8 +1245,8 @@@ static void set_connectivity_errors(str
                if (shallow_update && si->shallow_ref[cmd->index])
                        /* to be checked in update_shallow_ref() */
                        continue;
 -              if (!check_everything_connected(command_singleton_iterator,
 -                                              0, &singleton))
 +              if (!check_connected(command_singleton_iterator, &singleton,
 +                                   NULL))
                        continue;
                cmd->error_string = "missing necessary objects";
        }
@@@ -1401,15 -1313,11 +1401,15 @@@ cleanup
  
  static void execute_commands(struct command *commands,
                             const char *unpacker_error,
 -                           struct shallow_info *si)
 +                           struct shallow_info *si,
 +                           const struct string_list *push_options)
  {
 +      struct check_connected_options opt = CHECK_CONNECTED_INIT;
        struct command *cmd;
        unsigned char sha1[20];
        struct iterate_data data;
 +      struct async muxer;
 +      int err_fd = 0;
  
        if (unpacker_error) {
                for (cmd = commands; cmd; cmd = cmd->next)
                return;
        }
  
 +      if (use_sideband) {
 +              memset(&muxer, 0, sizeof(muxer));
 +              muxer.proc = copy_to_sideband;
 +              muxer.in = -1;
 +              if (!start_async(&muxer))
 +                      err_fd = muxer.in;
 +              /* ...else, continue without relaying sideband */
 +      }
 +
        data.cmds = commands;
        data.si = si;
 -      if (check_everything_connected(iterate_receive_command_list, 0, &data))
 +      opt.err_fd = err_fd;
 +      opt.progress = err_fd && !quiet;
 +      if (check_connected(iterate_receive_command_list, &data, &opt))
                set_connectivity_errors(commands, si);
  
 +      if (use_sideband)
 +              finish_async(&muxer);
 +
        reject_updates_to_hidden(commands);
  
 -      if (run_receive_hook(commands, "pre-receive", 0)) {
 +      if (run_receive_hook(commands, "pre-receive", 0, push_options)) {
                for (cmd = commands; cmd; cmd = cmd->next) {
                        if (!cmd->error_string)
                                cmd->error_string = "pre-receive hook declined";
@@@ -1478,11 -1372,9 +1478,9 @@@ static struct command **queue_command(s
  
        refname = line + 82;
        reflen = linelen - 82;
-       cmd = xcalloc(1, st_add3(sizeof(struct command), reflen, 1));
+       FLEX_ALLOC_MEM(cmd, ref_name, refname, reflen);
        hashcpy(cmd->old_sha1, old_sha1);
        hashcpy(cmd->new_sha1, new_sha1);
-       memcpy(cmd->ref_name, refname, reflen);
-       cmd->ref_name[reflen] = '\0';
        *tail = cmd;
        return &cmd->next;
  }
@@@ -1542,9 -1434,6 +1540,9 @@@ static struct command *read_head_info(s
                        if (advertise_atomic_push
                            && parse_feature_request(feature_list, "atomic"))
                                use_atomic = 1;
 +                      if (advertise_push_options
 +                          && parse_feature_request(feature_list, "push-options"))
 +                              use_push_options = 1;
                }
  
                if (!strcmp(line, "push-cert")) {
        return commands;
  }
  
 +static void read_push_options(struct string_list *options)
 +{
 +      while (1) {
 +              char *line;
 +              int len;
 +
 +              line = packet_read_line(0, &len);
 +
 +              if (!line)
 +                      break;
 +
 +              string_list_append(options, line);
 +      }
 +}
 +
  static const char *parse_pack_header(struct pack_header *hdr)
  {
        switch (read_pack_header(0, hdr)) {
@@@ -1669,14 -1543,10 +1667,14 @@@ static const char *unpack(int err_fd, s
                                 (uintmax_t)getpid(),
                                 hostname);
  
 +              if (!quiet && err_fd)
 +                      argv_array_push(&child.args, "--show-resolving-progress");
 +              if (use_sideband)
 +                      argv_array_push(&child.args, "--report-end-of-input");
                if (fsck_objects)
                        argv_array_pushf(&child.args, "--strict%s",
                                fsck_msg_types.buf);
 -              if (fix_thin)
 +              if (!reject_thin)
                        argv_array_push(&child.args, "--fix-thin");
                child.out = -1;
                child.err = err_fd;
@@@ -1702,7 -1572,6 +1700,7 @@@ static const char *unpack_with_sideband
        if (!use_sideband)
                return unpack(0, si);
  
 +      use_keepalive = KEEPALIVE_AFTER_NUL;
        memset(&muxer, 0, sizeof(muxer));
        muxer.proc = copy_to_sideband;
        muxer.in = -1;
@@@ -1836,29 -1705,45 +1834,29 @@@ static int delete_only(struct command *
  int cmd_receive_pack(int argc, const char **argv, const char *prefix)
  {
        int advertise_refs = 0;
 -      int i;
        struct command *commands;
        struct sha1_array shallow = SHA1_ARRAY_INIT;
        struct sha1_array ref = SHA1_ARRAY_INIT;
        struct shallow_info si;
  
 -      packet_trace_identity("receive-pack");
 +      struct option options[] = {
 +              OPT__QUIET(&quiet, N_("quiet")),
 +              OPT_HIDDEN_BOOL(0, "stateless-rpc", &stateless_rpc, NULL),
 +              OPT_HIDDEN_BOOL(0, "advertise-refs", &advertise_refs, NULL),
 +              OPT_HIDDEN_BOOL(0, "reject-thin-pack-for-testing", &reject_thin, NULL),
 +              OPT_END()
 +      };
  
 -      argv++;
 -      for (i = 1; i < argc; i++) {
 -              const char *arg = *argv++;
 +      packet_trace_identity("receive-pack");
  
 -              if (*arg == '-') {
 -                      if (!strcmp(arg, "--quiet")) {
 -                              quiet = 1;
 -                              continue;
 -                      }
 +      argc = parse_options(argc, argv, prefix, options, receive_pack_usage, 0);
  
 -                      if (!strcmp(arg, "--advertise-refs")) {
 -                              advertise_refs = 1;
 -                              continue;
 -                      }
 -                      if (!strcmp(arg, "--stateless-rpc")) {
 -                              stateless_rpc = 1;
 -                              continue;
 -                      }
 -                      if (!strcmp(arg, "--reject-thin-pack-for-testing")) {
 -                              fix_thin = 0;
 -                              continue;
 -                      }
 +      if (argc > 1)
 +              usage_msg_opt(_("Too many arguments."), receive_pack_usage, options);
 +      if (argc == 0)
 +              usage_msg_opt(_("You must specify a directory."), receive_pack_usage, options);
  
 -                      usage(receive_pack_usage);
 -              }
 -              if (service_dir)
 -                      usage(receive_pack_usage);
 -              service_dir = arg;
 -      }
 -      if (!service_dir)
 -              usage(receive_pack_usage);
 +      service_dir = argv[0];
  
        setup_path();
  
  
        if ((commands = read_head_info(&shallow)) != NULL) {
                const char *unpack_status = NULL;
 +              struct string_list push_options = STRING_LIST_INIT_DUP;
 +
 +              if (use_push_options)
 +                      read_push_options(&push_options);
  
                prepare_shallow_info(&si, &shallow);
                if (!si.nr_ours && !si.nr_theirs)
                        unpack_status = unpack_with_sideband(&si);
                        update_shallow_info(commands, &si, &ref);
                }
 -              execute_commands(commands, unpack_status, &si);
 +              use_keepalive = KEEPALIVE_ALWAYS;
 +              execute_commands(commands, unpack_status, &si,
 +                               &push_options);
                if (pack_lockfile)
                        unlink_or_warn(pack_lockfile);
                if (report_status)
                        report(commands, unpack_status);
 -              run_receive_hook(commands, "post-receive", 1);
 +              run_receive_hook(commands, "post-receive", 1,
 +                               &push_options);
                run_update_post_hook(commands);
 +              if (push_options.nr)
 +                      string_list_clear(&push_options, 0);
                if (auto_gc) {
                        const char *argv_gc_auto[] = {
                                "gc", "--auto", "--quiet", NULL,
                        };
 -                      int opt = RUN_GIT_CMD | RUN_COMMAND_STDOUT_TO_STDERR;
 +                      struct child_process proc = CHILD_PROCESS_INIT;
 +
 +                      proc.no_stdin = 1;
 +                      proc.stdout_to_stderr = 1;
 +                      proc.err = use_sideband ? -1 : 0;
 +                      proc.git_cmd = 1;
 +                      proc.argv = argv_gc_auto;
 +
                        close_all_packs();
 -                      run_command_v_opt(argv_gc_auto, opt);
 +                      if (!start_command(&proc)) {
 +                              if (use_sideband)
 +                                      copy_to_sideband(proc.err, -1, NULL);
 +                              finish_command(&proc);
 +                      }
                }
                if (auto_update_server_info)
                        update_server_info(0);
diff --combined git-compat-util.h
index 590bfddf73238d37f7b2d831a6e46ed608c005ce,17918d028a25a19bc4fd55db51b9418b2881b68a..f52e00b58057c7bfe040e516835a42d117be1de2
@@@ -279,6 -279,9 +279,6 @@@ extern char *gitdirname(char *)
  #endif
  #include <openssl/ssl.h>
  #include <openssl/err.h>
 -#ifdef NO_HMAC_CTX_CLEANUP
 -#define HMAC_CTX_cleanup HMAC_cleanup
 -#endif
  #endif
  
  /* On most systems <netdb.h> would have given us this, but
  #define _PATH_DEFPATH "/usr/local/bin:/usr/bin:/bin"
  #endif
  
 -#ifndef STRIP_EXTENSION
 -#define STRIP_EXTENSION ""
 -#endif
 -
  #ifndef has_dos_drive_prefix
  static inline int git_has_dos_drive_prefix(const char *path)
  {
@@@ -409,9 -416,7 +409,9 @@@ extern NORETURN void usagef(const char 
  extern NORETURN void die(const char *err, ...) __attribute__((format (printf, 1, 2)));
  extern NORETURN void die_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
  extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
 +extern int error_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
  extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
 +extern void warning_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
  
  #ifndef NO_OPENSSL
  #ifdef APPLE_COMMON_CRYPTO
@@@ -473,23 -478,6 +473,23 @@@ static inline int skip_prefix(const cha
        return 0;
  }
  
 +/*
 + * Like skip_prefix, but promises never to read past "len" bytes of the input
 + * buffer, and returns the remaining number of bytes in "out" via "outlen".
 + */
 +static inline int skip_prefix_mem(const char *buf, size_t len,
 +                                const char *prefix,
 +                                const char **out, size_t *outlen)
 +{
 +      size_t prefix_len = strlen(prefix);
 +      if (prefix_len <= len && !memcmp(buf, prefix, prefix_len)) {
 +              *out = buf + prefix_len;
 +              *outlen = len - prefix_len;
 +              return 1;
 +      }
 +      return 0;
 +}
 +
  /*
   * If buf ends with suffix, return 1 and subtract the length of the suffix
   * from *len. Otherwise, return 0 and leave *len untouched.
@@@ -731,8 -719,8 +731,8 @@@ static inline size_t st_add(size_t a, s
                    (uintmax_t)a, (uintmax_t)b);
        return a + b;
  }
 -#define st_add3(a,b,c)   st_add((a),st_add((b),(c)))
 -#define st_add4(a,b,c,d) st_add((a),st_add3((b),(c),(d)))
 +#define st_add3(a,b,c)   st_add(st_add((a),(b)),(c))
 +#define st_add4(a,b,c,d) st_add(st_add3((a),(b),(c)),(d))
  
  static inline size_t st_mult(size_t a, size_t b)
  {
@@@ -815,7 -803,7 +815,7 @@@ extern FILE *fopen_for_writing(const ch
   * you can do:
   *
   *   struct foo *f;
-  *   FLEX_ALLOC_STR(f, name, src);
+  *   FLEXPTR_ALLOC_STR(f, name, src);
   *
   * and "name" will point to a block of memory after the struct, which will be
   * freed along with the struct (but the pointer can be repointed anywhere).
@@@ -1062,5 -1050,3 +1062,5 @@@ struct tm *git_gmtime_r(const time_t *
  #endif
  
  #endif
 +
 +extern int cmd_main(int, const char **);