Merge branch 'ph/transport-with-gitfile'
authorJunio C Hamano <gitster@pobox.com>
Fri, 21 Oct 2011 23:04:32 +0000 (16:04 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 21 Oct 2011 23:04:32 +0000 (16:04 -0700)
* ph/transport-with-gitfile:
Fix is_gitfile() for files too small or larger than PATH_MAX to be a gitfile
Add test showing git-fetch groks gitfiles
Teach transport about the gitfile mechanism
Learn to handle gitfiles in enter_repo
enter_repo: do not modify input

1  2 
cache.h
daemon.c
transport.c
diff --combined cache.h
index be07ec70863cae3f6e1c9d5dbc6dc555e444e30a,a7e4de15a2fe7d3a969253d11536f005962529b4..42884ec62c1e920f4aa65693c0efd773c1bc94cf
+++ b/cache.h
@@@ -168,7 -168,6 +168,7 @@@ struct cache_entry 
        unsigned int ce_flags;
        unsigned char sha1[20];
        struct cache_entry *next;
 +      struct cache_entry *dir_next;
        char name[FLEX_ARRAY]; /* more */
  };
  
@@@ -440,12 -439,12 +440,12 @@@ extern const char *get_git_namespace(vo
  extern const char *strip_namespace(const char *namespaced_ref);
  extern const char *get_git_work_tree(void);
  extern const char *read_gitfile(const char *path);
 +extern const char *resolve_gitdir(const char *suspect);
  extern void set_git_work_tree(const char *tree);
  
  #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
  
  extern const char **get_pathspec(const char *prefix, const char **pathspec);
 -extern const char *pathspec_prefix(const char *prefix, const char **pathspec);
  extern void setup_work_tree(void);
  extern const char *setup_git_directory_gently(int *);
  extern const char *setup_git_directory(void);
@@@ -590,7 -589,6 +590,7 @@@ extern int warn_ambiguous_refs
  extern int shared_repository;
  extern const char *apply_default_whitespace;
  extern const char *apply_default_ignorewhitespace;
 +extern const char *git_attributes_file;
  extern int zlib_compression_level;
  extern int core_compression_level;
  extern int core_compression_seen;
@@@ -736,7 -734,7 +736,7 @@@ int safe_create_leading_directories(cha
  int safe_create_leading_directories_const(const char *path);
  int mkdir_in_gitdir(const char *path);
  extern char *expand_user_path(const char *path);
- char *enter_repo(char *path, int strict);
+ const char *enter_repo(const char *path, int strict);
  static inline int is_absolute_path(const char *path)
  {
        return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
@@@ -821,51 -819,10 +821,51 @@@ static inline int get_sha1_with_context
  {
        return get_sha1_with_context_1(str, sha1, orc, 0, NULL);
  }
 +
 +/*
 + * Try to read a SHA1 in hexadecimal format from the 40 characters
 + * starting at hex.  Write the 20-byte result to sha1 in binary form.
 + * Return 0 on success.  Reading stops if a NUL is encountered in the
 + * input, so it is safe to pass this function an arbitrary
 + * null-terminated string.
 + */
  extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 +
  extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
  extern int read_ref(const char *filename, unsigned char *sha1);
 -extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
 +
 +/*
 + * Resolve a reference, recursively following symbolic refererences.
 + *
 + * Store the referred-to object's name in sha1 and return the name of
 + * the non-symbolic reference that ultimately pointed at it.  The
 + * return value, if not NULL, is a pointer into either a static buffer
 + * or the input ref.
 + *
 + * If the reference cannot be resolved to an object, the behavior
 + * depends on the "reading" argument:
 + *
 + * - If reading is set, return NULL.
 + *
 + * - If reading is not set, clear sha1 and return the name of the last
 + *   reference name in the chain, which will either be a non-symbolic
 + *   reference or an undefined reference.  If this is a prelude to
 + *   "writing" to the ref, the return value is the name of the ref
 + *   that will actually be created or changed.
 + *
 + * If flag is non-NULL, set the value that it points to the
 + * combination of REF_ISPACKED (if the reference was found among the
 + * packed references) and REF_ISSYMREF (if the initial reference was a
 + * symbolic reference).
 + *
 + * If ref is not a properly-formatted, normalized reference, return
 + * NULL.  If more than MAXDEPTH recursive symbolic lookups are needed,
 + * give up and return NULL.
 + *
 + * errno is sometimes set on errors, but not always.
 + */
 +extern const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag);
 +
  extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
  extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
  extern int interpret_branch_name(const char *str, struct strbuf *);
@@@ -1119,11 -1076,9 +1119,11 @@@ extern int git_config_bool(const char *
  extern int git_config_maybe_bool(const char *, const char *);
  extern int git_config_string(const char **, const char *, const char *);
  extern int git_config_pathname(const char **, const char *, const char *);
 +extern int git_config_set_in_file(const char *, const char *, const char *);
  extern int git_config_set(const char *, const char *);
  extern int git_config_parse_key(const char *, char **, int *);
  extern int git_config_set_multivar(const char *, const char *, const char *, int);
 +extern int git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
  extern int git_config_rename_section(const char *, const char *);
  extern const char *git_etc_gitconfig(void);
  extern int check_repository_format_version(const char *var, const char *value, void *cb);
diff --combined daemon.c
index 5a1086198b5f3780b5bc348cae78af12d8775cad,9253192aec5b5d9d5085cfa828a254551f6d7f81..91c4d9bdf3ce784f80645ab4b145a98f1360e7a5
+++ b/daemon.c
@@@ -108,11 -108,11 +108,11 @@@ static void NORETURN daemon_die(const c
        exit(1);
  }
  
- static char *path_ok(char *directory)
+ static const char *path_ok(char *directory)
  {
        static char rpath[PATH_MAX];
        static char interp_path[PATH_MAX];
-       char *path;
+       const char *path;
        char *dir;
  
        dir = directory;
@@@ -257,11 -257,11 +257,11 @@@ static int run_service(char *dir, struc
        if (!enabled && !service->overridable) {
                logerror("'%s': service not enabled.", service->name);
                errno = EACCES;
 -              return -1;
 +              goto failed;
        }
  
        if (!(path = path_ok(dir)))
 -              return -1;
 +              goto failed;
  
        /*
         * Security on the cheap.
        if (!export_all_trees && access("git-daemon-export-ok", F_OK)) {
                logerror("'%s': repository not exported.", path);
                errno = EACCES;
 -              return -1;
 +              goto failed;
        }
  
        if (service->overridable) {
                logerror("'%s': service not enabled for '%s'",
                         service->name, path);
                errno = EACCES;
 -              return -1;
 +              goto failed;
        }
  
        /*
        signal(SIGTERM, SIG_IGN);
  
        return service->fn();
 +
 +failed:
 +      packet_write(1, "ERR %s: access denied", dir);
 +      return -1;
  }
  
  static void copy_to_log(int fd)
@@@ -738,29 -734,6 +738,29 @@@ struct socketlist 
        size_t alloc;
  };
  
 +static const char *ip2str(int family, struct sockaddr *sin, socklen_t len)
 +{
 +#ifdef NO_IPV6
 +      static char ip[INET_ADDRSTRLEN];
 +#else
 +      static char ip[INET6_ADDRSTRLEN];
 +#endif
 +
 +      switch (family) {
 +#ifndef NO_IPV6
 +      case AF_INET6:
 +              inet_ntop(family, &((struct sockaddr_in6*)sin)->sin6_addr, ip, len);
 +              break;
 +#endif
 +      case AF_INET:
 +              inet_ntop(family, &((struct sockaddr_in*)sin)->sin_addr, ip, len);
 +              break;
 +      default:
 +              strcpy(ip, "<unknown>");
 +      }
 +      return ip;
 +}
 +
  #ifndef NO_IPV6
  
  static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
  #endif
  
                if (set_reuse_addr(sockfd)) {
 +                      logerror("Could not set SO_REUSEADDR: %s", strerror(errno));
                        close(sockfd);
                        continue;
                }
  
                if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
 +                      logerror("Could not bind to %s: %s",
 +                               ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen),
 +                               strerror(errno));
                        close(sockfd);
                        continue;       /* not fatal */
                }
                if (listen(sockfd, 5) < 0) {
 +                      logerror("Could not listen to %s: %s",
 +                               ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen),
 +                               strerror(errno));
                        close(sockfd);
                        continue;       /* not fatal */
                }
@@@ -869,23 -835,16 +869,23 @@@ static int setup_named_sock(char *liste
                return 0;
  
        if (set_reuse_addr(sockfd)) {
 +              logerror("Could not set SO_REUSEADDR: %s", strerror(errno));
                close(sockfd);
                return 0;
        }
  
        if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {
 +              logerror("Could not listen to %s: %s",
 +                       ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)),
 +                       strerror(errno));
                close(sockfd);
                return 0;
        }
  
        if (listen(sockfd, 5) < 0) {
 +              logerror("Could not listen to %s: %s",
 +                       ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)),
 +                       strerror(errno));
                close(sockfd);
                return 0;
        }
diff --combined transport.c
index c048ef179b732c2b1e1ca6531b196b313f0f05ee,a2b1a258dc0b7ffd9d3988e65811e4e504808d90..57138d908a5749d378af441e8d3cfe8150b27271
@@@ -432,8 -432,7 +432,8 @@@ static int fetch_refs_from_bundle(struc
                               int nr_heads, struct ref **to_fetch)
  {
        struct bundle_transport_data *data = transport->data;
 -      return unbundle(&data->header, data->fd);
 +      return unbundle(&data->header, data->fd,
 +                      transport->progress ? BUNDLE_VERBOSE : 0);
  }
  
  static int close_bundle(struct transport *transport)
@@@ -755,10 -754,18 +755,10 @@@ void transport_verify_remote_names(int 
                        continue;
  
                remote = remote ? (remote + 1) : local;
 -              switch (check_ref_format(remote)) {
 -              case 0: /* ok */
 -              case CHECK_REF_FORMAT_ONELEVEL:
 -                      /* ok but a single level -- that is fine for
 -                       * a match pattern.
 -                       */
 -              case CHECK_REF_FORMAT_WILDCARD:
 -                      /* ok but ends with a pattern-match character */
 -                      continue;
 -              }
 -              die("remote part of refspec is not a valid name in %s",
 -                  heads[i]);
 +              if (check_refname_format(remote,
 +                              REFNAME_ALLOW_ONELEVEL|REFNAME_REFSPEC_PATTERN))
 +                      die("remote part of refspec is not a valid name in %s",
 +                              heads[i]);
        }
  }
  
@@@ -859,6 -866,28 +859,28 @@@ static int is_local(const char *url
                has_dos_drive_prefix(url);
  }
  
+ static int is_gitfile(const char *url)
+ {
+       struct stat st;
+       char buf[9];
+       int fd, len;
+       if (stat(url, &st))
+               return 0;
+       if (!S_ISREG(st.st_mode))
+               return 0;
+       if (st.st_size < 10 || st.st_size > 9 + PATH_MAX)
+               return 0;
+       fd = open(url, O_RDONLY);
+       if (fd < 0)
+               die_errno("Error opening '%s'", url);
+       len = read_in_full(fd, buf, sizeof(buf));
+       close(fd);
+       if (len != sizeof(buf))
+               die("Error reading %s", url);
+       return !prefixcmp(buf, "gitdir: ");
+ }
  static int is_file(const char *url)
  {
        struct stat buf;
@@@ -907,7 -936,7 +929,7 @@@ struct transport *transport_get(struct 
                ret->fetch = fetch_objs_via_rsync;
                ret->push = rsync_transport_push;
                ret->smart_options = NULL;
-       } else if (is_local(url) && is_file(url)) {
+       } else if (is_local(url) && is_file(url) && !is_gitfile(url)) {
                struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
                ret->data = data;
                ret->get_refs_list = get_refs_from_bundle;