Skip to content

Commit ad89721

Browse files
author
Junio C Hamano
committed
fetch-pack: -k option to keep downloaded pack.
Split out the functions that deal with the socketpair after finishing git protocol handshake to receive the packed data into a separate file, and use it in fetch-pack to keep/explode the received pack data. We earlier had something like that on clone-pack side once, but the list discussion resulted in the decision that it makes sense to always keep the pack for clone-pack, so unpacking option is not enabled on the clone-pack side, but we later still could do so easily if we wanted to with this change. Signed-off-by: Junio C Hamano <[email protected]>
1 parent c054d64 commit ad89721

File tree

6 files changed

+206
-173
lines changed

6 files changed

+206
-173
lines changed

Documentation/git-fetch-pack.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ git-fetch-pack - Receive missing objects from another repository.
88

99
SYNOPSIS
1010
--------
11-
git-fetch-pack [-q] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
11+
git-fetch-pack [-q] [-k] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
1212

1313
DESCRIPTION
1414
-----------
@@ -29,6 +29,11 @@ OPTIONS
2929
Pass '-q' flag to 'git-unpack-objects'; this makes the
3030
cloning process less verbose.
3131

32+
-k::
33+
Do not invoke 'git-unpack-objects' on received data, but
34+
create a single packfile out of it instead, and store it
35+
in the object database.
36+
3237
--exec=<git-upload-pack>::
3338
Use this to specify the path to 'git-upload-pack' on the
3439
remote side, if is not found on your $PATH.

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ LIB_OBJS = \
175175
quote.o read-cache.o refs.o run-command.o \
176176
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
177177
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
178+
fetch-clone.o \
178179
$(DIFF_OBJS)
179180

180181
LIBS = $(LIB_FILE)

cache.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,4 +338,9 @@ extern char git_default_name[MAX_GITNAME];
338338
extern char git_commit_encoding[MAX_ENCODING_LENGTH];
339339

340340
extern int copy_fd(int ifd, int ofd);
341+
342+
/* Finish off pack transfer receiving end */
343+
extern int receive_unpack_pack(int fd[2], const char *me, int quiet);
344+
extern int receive_keep_pack(int fd[2], const char *me);
345+
341346
#endif /* CACHE_H */

clone-pack.c

Lines changed: 1 addition & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "cache.h"
22
#include "refs.h"
33
#include "pkt-line.h"
4-
#include <sys/wait.h>
54

65
static const char clone_pack_usage[] =
76
"git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
@@ -112,139 +111,6 @@ static void write_refs(struct ref *ref)
112111
free(head_path);
113112
}
114113

115-
static int finish_pack(const char *pack_tmp_name)
116-
{
117-
int pipe_fd[2];
118-
pid_t pid;
119-
char idx[PATH_MAX];
120-
char final[PATH_MAX];
121-
char hash[41];
122-
unsigned char sha1[20];
123-
char *cp;
124-
int err = 0;
125-
126-
if (pipe(pipe_fd) < 0)
127-
die("git-clone-pack: unable to set up pipe");
128-
129-
strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
130-
cp = strrchr(idx, '/');
131-
memcpy(cp, "/pidx", 5);
132-
133-
pid = fork();
134-
if (pid < 0)
135-
die("git-clone-pack: unable to fork off git-index-pack");
136-
if (!pid) {
137-
close(0);
138-
dup2(pipe_fd[1], 1);
139-
close(pipe_fd[0]);
140-
close(pipe_fd[1]);
141-
execlp("git-index-pack","git-index-pack",
142-
"-o", idx, pack_tmp_name, NULL);
143-
error("cannot exec git-index-pack <%s> <%s>",
144-
idx, pack_tmp_name);
145-
exit(1);
146-
}
147-
close(pipe_fd[1]);
148-
if (read(pipe_fd[0], hash, 40) != 40) {
149-
error("git-clone-pack: unable to read from git-index-pack");
150-
err = 1;
151-
}
152-
close(pipe_fd[0]);
153-
154-
for (;;) {
155-
int status, code;
156-
int retval = waitpid(pid, &status, 0);
157-
158-
if (retval < 0) {
159-
if (errno == EINTR)
160-
continue;
161-
error("waitpid failed (%s)", strerror(retval));
162-
goto error_die;
163-
}
164-
if (WIFSIGNALED(status)) {
165-
int sig = WTERMSIG(status);
166-
error("git-index-pack died of signal %d", sig);
167-
goto error_die;
168-
}
169-
if (!WIFEXITED(status)) {
170-
error("git-index-pack died of unnatural causes %d",
171-
status);
172-
goto error_die;
173-
}
174-
code = WEXITSTATUS(status);
175-
if (code) {
176-
error("git-index-pack died with error code %d", code);
177-
goto error_die;
178-
}
179-
if (err)
180-
goto error_die;
181-
break;
182-
}
183-
hash[40] = 0;
184-
if (get_sha1_hex(hash, sha1)) {
185-
error("git-index-pack reported nonsense '%s'", hash);
186-
goto error_die;
187-
}
188-
/* Now we have pack in pack_tmp_name[], and
189-
* idx in idx[]; rename them to their final names.
190-
*/
191-
snprintf(final, sizeof(final),
192-
"%s/pack/pack-%s.pack", get_object_directory(), hash);
193-
move_temp_to_file(pack_tmp_name, final);
194-
chmod(final, 0444);
195-
snprintf(final, sizeof(final),
196-
"%s/pack/pack-%s.idx", get_object_directory(), hash);
197-
move_temp_to_file(idx, final);
198-
chmod(final, 0444);
199-
return 0;
200-
201-
error_die:
202-
unlink(idx);
203-
unlink(pack_tmp_name);
204-
exit(1);
205-
}
206-
207-
static int clone_without_unpack(int fd[2])
208-
{
209-
char tmpfile[PATH_MAX];
210-
int ofd, ifd;
211-
212-
ifd = fd[0];
213-
snprintf(tmpfile, sizeof(tmpfile),
214-
"%s/pack/tmp-XXXXXX", get_object_directory());
215-
ofd = mkstemp(tmpfile);
216-
if (ofd < 0)
217-
return error("unable to create temporary file %s", tmpfile);
218-
219-
while (1) {
220-
char buf[8192];
221-
ssize_t sz, wsz, pos;
222-
sz = read(ifd, buf, sizeof(buf));
223-
if (sz == 0)
224-
break;
225-
if (sz < 0) {
226-
error("error reading pack (%s)", strerror(errno));
227-
close(ofd);
228-
unlink(tmpfile);
229-
return -1;
230-
}
231-
pos = 0;
232-
while (pos < sz) {
233-
wsz = write(ofd, buf + pos, sz - pos);
234-
if (wsz < 0) {
235-
error("error writing pack (%s)",
236-
strerror(errno));
237-
close(ofd);
238-
unlink(tmpfile);
239-
return -1;
240-
}
241-
pos += wsz;
242-
}
243-
}
244-
close(ofd);
245-
return finish_pack(tmpfile);
246-
}
247-
248114
static int clone_pack(int fd[2], int nr_match, char **match)
249115
{
250116
struct ref *refs;
@@ -257,7 +123,7 @@ static int clone_pack(int fd[2], int nr_match, char **match)
257123
}
258124
clone_handshake(fd, refs);
259125

260-
status = clone_without_unpack(fd);
126+
status = receive_keep_pack(fd, "git-clone-pack");
261127

262128
if (!status) {
263129
if (nr_match == 0)

fetch-clone.c

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#include "cache.h"
2+
#include <sys/wait.h>
3+
4+
static int finish_pack(const char *pack_tmp_name, const char *me)
5+
{
6+
int pipe_fd[2];
7+
pid_t pid;
8+
char idx[PATH_MAX];
9+
char final[PATH_MAX];
10+
char hash[41];
11+
unsigned char sha1[20];
12+
char *cp;
13+
int err = 0;
14+
15+
if (pipe(pipe_fd) < 0)
16+
die("%s: unable to set up pipe", me);
17+
18+
strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
19+
cp = strrchr(idx, '/');
20+
memcpy(cp, "/pidx", 5);
21+
22+
pid = fork();
23+
if (pid < 0)
24+
die("git-clone-pack: unable to fork off git-index-pack");
25+
if (!pid) {
26+
close(0);
27+
dup2(pipe_fd[1], 1);
28+
close(pipe_fd[0]);
29+
close(pipe_fd[1]);
30+
execlp("git-index-pack","git-index-pack",
31+
"-o", idx, pack_tmp_name, NULL);
32+
error("cannot exec git-index-pack <%s> <%s>",
33+
idx, pack_tmp_name);
34+
exit(1);
35+
}
36+
close(pipe_fd[1]);
37+
if (read(pipe_fd[0], hash, 40) != 40) {
38+
error("%s: unable to read from git-index-pack", me);
39+
err = 1;
40+
}
41+
close(pipe_fd[0]);
42+
43+
for (;;) {
44+
int status, code;
45+
int retval = waitpid(pid, &status, 0);
46+
47+
if (retval < 0) {
48+
if (errno == EINTR)
49+
continue;
50+
error("waitpid failed (%s)", strerror(retval));
51+
goto error_die;
52+
}
53+
if (WIFSIGNALED(status)) {
54+
int sig = WTERMSIG(status);
55+
error("git-index-pack died of signal %d", sig);
56+
goto error_die;
57+
}
58+
if (!WIFEXITED(status)) {
59+
error("git-index-pack died of unnatural causes %d",
60+
status);
61+
goto error_die;
62+
}
63+
code = WEXITSTATUS(status);
64+
if (code) {
65+
error("git-index-pack died with error code %d", code);
66+
goto error_die;
67+
}
68+
if (err)
69+
goto error_die;
70+
break;
71+
}
72+
hash[40] = 0;
73+
if (get_sha1_hex(hash, sha1)) {
74+
error("git-index-pack reported nonsense '%s'", hash);
75+
goto error_die;
76+
}
77+
/* Now we have pack in pack_tmp_name[], and
78+
* idx in idx[]; rename them to their final names.
79+
*/
80+
snprintf(final, sizeof(final),
81+
"%s/pack/pack-%s.pack", get_object_directory(), hash);
82+
move_temp_to_file(pack_tmp_name, final);
83+
chmod(final, 0444);
84+
snprintf(final, sizeof(final),
85+
"%s/pack/pack-%s.idx", get_object_directory(), hash);
86+
move_temp_to_file(idx, final);
87+
chmod(final, 0444);
88+
return 0;
89+
90+
error_die:
91+
unlink(idx);
92+
unlink(pack_tmp_name);
93+
exit(1);
94+
}
95+
96+
int receive_unpack_pack(int fd[2], const char *me, int quiet)
97+
{
98+
int status;
99+
pid_t pid;
100+
101+
pid = fork();
102+
if (pid < 0)
103+
die("%s: unable to fork off git-unpack-objects", me);
104+
if (!pid) {
105+
dup2(fd[0], 0);
106+
close(fd[0]);
107+
close(fd[1]);
108+
execlp("git-unpack-objects", "git-unpack-objects",
109+
quiet ? "-q" : NULL, NULL);
110+
die("git-unpack-objects exec failed");
111+
}
112+
close(fd[0]);
113+
close(fd[1]);
114+
while (waitpid(pid, &status, 0) < 0) {
115+
if (errno != EINTR)
116+
die("waiting for git-unpack-objects: %s",
117+
strerror(errno));
118+
}
119+
if (WIFEXITED(status)) {
120+
int code = WEXITSTATUS(status);
121+
if (code)
122+
die("git-unpack-objects died with error code %d",
123+
code);
124+
return 0;
125+
}
126+
if (WIFSIGNALED(status)) {
127+
int sig = WTERMSIG(status);
128+
die("git-unpack-objects died of signal %d", sig);
129+
}
130+
die("git-unpack-objects died of unnatural causes %d", status);
131+
}
132+
133+
int receive_keep_pack(int fd[2], const char *me)
134+
{
135+
char tmpfile[PATH_MAX];
136+
int ofd, ifd;
137+
138+
ifd = fd[0];
139+
snprintf(tmpfile, sizeof(tmpfile),
140+
"%s/pack/tmp-XXXXXX", get_object_directory());
141+
ofd = mkstemp(tmpfile);
142+
if (ofd < 0)
143+
return error("unable to create temporary file %s", tmpfile);
144+
145+
while (1) {
146+
char buf[8192];
147+
ssize_t sz, wsz, pos;
148+
sz = read(ifd, buf, sizeof(buf));
149+
if (sz == 0)
150+
break;
151+
if (sz < 0) {
152+
error("error reading pack (%s)", strerror(errno));
153+
close(ofd);
154+
unlink(tmpfile);
155+
return -1;
156+
}
157+
pos = 0;
158+
while (pos < sz) {
159+
wsz = write(ofd, buf + pos, sz - pos);
160+
if (wsz < 0) {
161+
error("error writing pack (%s)",
162+
strerror(errno));
163+
close(ofd);
164+
unlink(tmpfile);
165+
return -1;
166+
}
167+
pos += wsz;
168+
}
169+
}
170+
close(ofd);
171+
return finish_pack(tmpfile, me);
172+
}

0 commit comments

Comments
 (0)