| /* | |
| * Copyright (C) 2005 Junio C Hamano | |
| */ | |
| #include "cache.h" | |
| #include "commit.h" | |
| #include "pull.h" | |
| static int use_link = 0; | |
| static int use_symlink = 0; | |
| static int use_filecopy = 1; | |
| static char *path; /* "Remote" git repository */ | |
| void prefetch(unsigned char *sha1) | |
| { | |
| } | |
| static struct packed_git *packs = NULL; | |
| static void setup_index(unsigned char *sha1) | |
| { | |
| struct packed_git *new_pack; | |
| char filename[PATH_MAX]; | |
| strcpy(filename, path); | |
| strcat(filename, "/objects/pack/pack-"); | |
| strcat(filename, sha1_to_hex(sha1)); | |
| strcat(filename, ".idx"); | |
| new_pack = parse_pack_index_file(sha1, filename); | |
| new_pack->next = packs; | |
| packs = new_pack; | |
| } | |
| static int setup_indices(void) | |
| { | |
| DIR *dir; | |
| struct dirent *de; | |
| char filename[PATH_MAX]; | |
| unsigned char sha1[20]; | |
| sprintf(filename, "%s/objects/pack/", path); | |
| dir = opendir(filename); | |
| while ((de = readdir(dir)) != NULL) { | |
| int namelen = strlen(de->d_name); | |
| if (namelen != 50 || | |
| strcmp(de->d_name + namelen - 5, ".pack")) | |
| continue; | |
| get_sha1_hex(de->d_name + 5, sha1); | |
| setup_index(sha1); | |
| } | |
| return 0; | |
| } | |
| static int copy_file(const char *source, const char *dest, const char *hex) | |
| { | |
| if (use_link) { | |
| if (!link(source, dest)) { | |
| pull_say("link %s\n", hex); | |
| return 0; | |
| } | |
| /* If we got ENOENT there is no point continuing. */ | |
| if (errno == ENOENT) { | |
| fprintf(stderr, "does not exist %s\n", source); | |
| return -1; | |
| } | |
| } | |
| if (use_symlink && !symlink(source, dest)) { | |
| pull_say("symlink %s\n", hex); | |
| return 0; | |
| } | |
| if (use_filecopy) { | |
| int ifd, ofd, status; | |
| struct stat st; | |
| void *map; | |
| ifd = open(source, O_RDONLY); | |
| if (ifd < 0 || fstat(ifd, &st) < 0) { | |
| close(ifd); | |
| fprintf(stderr, "cannot open %s\n", source); | |
| return -1; | |
| } | |
| map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, ifd, 0); | |
| close(ifd); | |
| if (map == MAP_FAILED) { | |
| fprintf(stderr, "cannot mmap %s\n", source); | |
| return -1; | |
| } | |
| ofd = open(dest, O_WRONLY | O_CREAT | O_EXCL, 0666); | |
| status = ((ofd < 0) || | |
| (write(ofd, map, st.st_size) != st.st_size)); | |
| munmap(map, st.st_size); | |
| close(ofd); | |
| if (status) | |
| fprintf(stderr, "cannot write %s\n", dest); | |
| else | |
| pull_say("copy %s\n", hex); | |
| return status; | |
| } | |
| fprintf(stderr, "failed to copy %s with given copy methods.\n", hex); | |
| return -1; | |
| } | |
| static int fetch_pack(const unsigned char *sha1) | |
| { | |
| struct packed_git *target; | |
| char filename[PATH_MAX]; | |
| if (setup_indices()) | |
| return -1; | |
| target = find_sha1_pack(sha1, packs); | |
| if (!target) | |
| return error("Couldn't find %s: not separate or in any pack", | |
| sha1_to_hex(sha1)); | |
| if (get_verbosely) { | |
| fprintf(stderr, "Getting pack %s\n", | |
| sha1_to_hex(target->sha1)); | |
| fprintf(stderr, " which contains %s\n", | |
| sha1_to_hex(sha1)); | |
| } | |
| sprintf(filename, "%s/objects/pack/pack-%s.pack", | |
| path, sha1_to_hex(target->sha1)); | |
| copy_file(filename, sha1_pack_name(target->sha1), | |
| sha1_to_hex(target->sha1)); | |
| sprintf(filename, "%s/objects/pack/pack-%s.idx", | |
| path, sha1_to_hex(target->sha1)); | |
| copy_file(filename, sha1_pack_index_name(target->sha1), | |
| sha1_to_hex(target->sha1)); | |
| install_packed_git(target); | |
| return 0; | |
| } | |
| static int fetch_file(const unsigned char *sha1) | |
| { | |
| static int object_name_start = -1; | |
| static char filename[PATH_MAX]; | |
| char *hex = sha1_to_hex(sha1); | |
| const char *dest_filename = sha1_file_name(sha1); | |
| if (object_name_start < 0) { | |
| strcpy(filename, path); /* e.g. git.git */ | |
| strcat(filename, "/objects/"); | |
| object_name_start = strlen(filename); | |
| } | |
| filename[object_name_start+0] = hex[0]; | |
| filename[object_name_start+1] = hex[1]; | |
| filename[object_name_start+2] = '/'; | |
| strcpy(filename + object_name_start + 3, hex + 2); | |
| return copy_file(filename, dest_filename, hex); | |
| } | |
| int fetch(unsigned char *sha1) | |
| { | |
| return fetch_file(sha1) && fetch_pack(sha1); | |
| } | |
| int fetch_ref(char *ref, unsigned char *sha1) | |
| { | |
| static int ref_name_start = -1; | |
| static char filename[PATH_MAX]; | |
| static char hex[41]; | |
| int ifd; | |
| if (ref_name_start < 0) { | |
| sprintf(filename, "%s/refs/", path); | |
| ref_name_start = strlen(filename); | |
| } | |
| strcpy(filename + ref_name_start, ref); | |
| ifd = open(filename, O_RDONLY); | |
| if (ifd < 0) { | |
| close(ifd); | |
| fprintf(stderr, "cannot open %s\n", filename); | |
| return -1; | |
| } | |
| if (read(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) { | |
| close(ifd); | |
| fprintf(stderr, "cannot read from %s\n", filename); | |
| return -1; | |
| } | |
| close(ifd); | |
| pull_say("ref %s\n", sha1_to_hex(sha1)); | |
| return 0; | |
| } | |
| static const char local_pull_usage[] = | |
| "git-local-pull [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] [-l] [-s] [-n] commit-id path"; | |
| /* | |
| * By default we only use file copy. | |
| * If -l is specified, a hard link is attempted. | |
| * If -s is specified, then a symlink is attempted. | |
| * If -n is _not_ specified, then a regular file-to-file copy is done. | |
| */ | |
| int main(int argc, char **argv) | |
| { | |
| char *commit_id; | |
| int arg = 1; | |
| while (arg < argc && argv[arg][0] == '-') { | |
| if (argv[arg][1] == 't') | |
| get_tree = 1; | |
| else if (argv[arg][1] == 'c') | |
| get_history = 1; | |
| else if (argv[arg][1] == 'a') { | |
| get_all = 1; | |
| get_tree = 1; | |
| get_history = 1; | |
| } | |
| else if (argv[arg][1] == 'l') | |
| use_link = 1; | |
| else if (argv[arg][1] == 's') | |
| use_symlink = 1; | |
| else if (argv[arg][1] == 'n') | |
| use_filecopy = 0; | |
| else if (argv[arg][1] == 'v') | |
| get_verbosely = 1; | |
| else if (argv[arg][1] == 'w') | |
| write_ref = argv[++arg]; | |
| else | |
| usage(local_pull_usage); | |
| arg++; | |
| } | |
| if (argc < arg + 2) | |
| usage(local_pull_usage); | |
| commit_id = argv[arg]; | |
| path = argv[arg + 1]; | |
| if (pull(commit_id)) | |
| return 1; | |
| return 0; | |
| } |