Merge branch 'ph/transport-with-gitfile'

* 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
maint
Junio C Hamano 2011-10-21 16:04:32 -07:00
commit afd6284a7f
5 changed files with 58 additions and 20 deletions

View File

@ -736,7 +736,7 @@ int safe_create_leading_directories(char *path);
int safe_create_leading_directories_const(const char *path); int safe_create_leading_directories_const(const char *path);
int mkdir_in_gitdir(const char *path); int mkdir_in_gitdir(const char *path);
extern char *expand_user_path(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) static inline int is_absolute_path(const char *path)
{ {
return is_dir_sep(path[0]) || has_dos_drive_prefix(path); return is_dir_sep(path[0]) || has_dos_drive_prefix(path);

View File

@ -108,11 +108,11 @@ static void NORETURN daemon_die(const char *err, va_list params)
exit(1); exit(1);
} }


static char *path_ok(char *directory) static const char *path_ok(char *directory)
{ {
static char rpath[PATH_MAX]; static char rpath[PATH_MAX];
static char interp_path[PATH_MAX]; static char interp_path[PATH_MAX];
char *path; const char *path;
char *dir; char *dir;


dir = directory; dir = directory;

34
path.c
View File

@ -283,7 +283,7 @@ return_null:
* links. User relative paths are also returned as they are given, * links. User relative paths are also returned as they are given,
* except DWIM suffixing. * except DWIM suffixing.
*/ */
char *enter_repo(char *path, int strict) const char *enter_repo(const char *path, int strict)
{ {
static char used_path[PATH_MAX]; static char used_path[PATH_MAX];
static char validated_path[PATH_MAX]; static char validated_path[PATH_MAX];
@ -295,16 +295,19 @@ char *enter_repo(char *path, int strict)
static const char *suffix[] = { static const char *suffix[] = {
".git/.git", "/.git", ".git", "", NULL, ".git/.git", "/.git", ".git", "", NULL,
}; };
const char *gitfile;
int len = strlen(path); int len = strlen(path);
int i; int i;
while ((1 < len) && (path[len-1] == '/')) { while ((1 < len) && (path[len-1] == '/'))
path[len-1] = 0;
len--; len--;
}
if (PATH_MAX <= len) if (PATH_MAX <= len)
return NULL; return NULL;
if (path[0] == '~') { strncpy(used_path, path, len); used_path[len] = 0 ;
char *newpath = expand_user_path(path); strcpy(validated_path, used_path);

if (used_path[0] == '~') {
char *newpath = expand_user_path(used_path);
if (!newpath || (PATH_MAX - 10 < strlen(newpath))) { if (!newpath || (PATH_MAX - 10 < strlen(newpath))) {
free(newpath); free(newpath);
return NULL; return NULL;
@ -316,24 +319,23 @@ char *enter_repo(char *path, int strict)
* anyway. * anyway.
*/ */
strcpy(used_path, newpath); free(newpath); strcpy(used_path, newpath); free(newpath);
strcpy(validated_path, path);
path = used_path;
} }
else if (PATH_MAX - 10 < len) else if (PATH_MAX - 10 < len)
return NULL; return NULL;
else { len = strlen(used_path);
path = strcpy(used_path, path);
strcpy(validated_path, path);
}
len = strlen(path);
for (i = 0; suffix[i]; i++) { for (i = 0; suffix[i]; i++) {
strcpy(path + len, suffix[i]); strcpy(used_path + len, suffix[i]);
if (!access(path, F_OK)) { if (!access(used_path, F_OK)) {
strcat(validated_path, suffix[i]); strcat(validated_path, suffix[i]);
break; break;
} }
} }
if (!suffix[i] || chdir(path)) if (!suffix[i])
return NULL;
gitfile = read_gitfile(used_path) ;
if (gitfile)
strcpy(used_path, gitfile);
if (chdir(used_path))
return NULL; return NULL;
path = validated_path; path = validated_path;
} }

View File

@ -206,6 +206,20 @@ test_expect_success 'clone from .git file' '
git clone dst/.git dst2 git clone dst/.git dst2
' '


test_expect_success 'fetch from .git gitfile' '
(
cd dst2 &&
git fetch ../dst/.git
)
'

test_expect_success 'fetch from gitfile parent' '
(
cd dst2 &&
git fetch ../dst
)
'

test_expect_success 'clone separate gitdir where target already exists' ' test_expect_success 'clone separate gitdir where target already exists' '
rm -rf dst && rm -rf dst &&
test_must_fail git clone --separate-git-dir realgitdir src dst test_must_fail git clone --separate-git-dir realgitdir src dst

View File

@ -859,6 +859,28 @@ static int is_local(const char *url)
has_dos_drive_prefix(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) static int is_file(const char *url)
{ {
struct stat buf; struct stat buf;
@ -907,7 +929,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
ret->fetch = fetch_objs_via_rsync; ret->fetch = fetch_objs_via_rsync;
ret->push = rsync_transport_push; ret->push = rsync_transport_push;
ret->smart_options = NULL; 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)); struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
ret->data = data; ret->data = data;
ret->get_refs_list = get_refs_from_bundle; ret->get_refs_list = get_refs_from_bundle;