зеркало из https://github.com/microsoft/git.git
Merge branch 'jc/archive'
* jc/archive: git-tar-tree: devolve git-tar-tree into a wrapper for git-archive git-archive: inline default_parse_extra() builtin-archive.c: rename remote_request() to extract_remote_arg() upload-archive: monitor child communication more carefully. Add sideband status report to git-archive protocol Prepare larger packet buffer for upload-pack protocol. Teach --exec to git-archive --remote Add --verbose to git-archive archive: force line buffered output to stderr Use xstrdup instead of strdup in builtin-{tar,zip}-tree.c Move sideband server side support into reusable form. Move sideband client side support into reusable form. archive: allow remote to have more formats than we understand. git-archive: make compression level of ZIP archives configurable Add git-upload-archive git-archive: wire up ZIP format. git-archive: wire up TAR format. Add git-archive
This commit is contained in:
Коммит
4d69065d3a
|
@ -8,6 +8,7 @@ git-apply
|
|||
git-applymbox
|
||||
git-applypatch
|
||||
git-archimport
|
||||
git-archive
|
||||
git-bisect
|
||||
git-branch
|
||||
git-cat-file
|
||||
|
@ -118,6 +119,7 @@ git-unpack-objects
|
|||
git-update-index
|
||||
git-update-ref
|
||||
git-update-server-info
|
||||
git-upload-archive
|
||||
git-upload-pack
|
||||
git-upload-tar
|
||||
git-var
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
git-archive(1)
|
||||
==============
|
||||
|
||||
NAME
|
||||
----
|
||||
git-archive - Creates a archive of the files in the named tree
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
|
||||
[--remote=<repo>] <tree-ish> [path...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Creates an archive of the specified format containing the tree
|
||||
structure for the named tree. If <prefix> is specified it is
|
||||
prepended to the filenames in the archive.
|
||||
|
||||
'git-archive' behaves differently when given a tree ID versus when
|
||||
given a commit ID or tag ID. In the first case the current time is
|
||||
used as modification time of each file in the archive. In the latter
|
||||
case the commit time as recorded in the referenced commit object is
|
||||
used instead. Additionally the commit ID is stored in a global
|
||||
extended pax header if the tar format is used; it can be extracted
|
||||
using 'git-get-tar-commit-id'. In ZIP files it is stored as a file
|
||||
comment.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
--format=<fmt>::
|
||||
Format of the resulting archive: 'tar', 'zip'...
|
||||
|
||||
--list::
|
||||
Show all available formats.
|
||||
|
||||
--prefix=<prefix>/::
|
||||
Prepend <prefix>/ to each filename in the archive.
|
||||
|
||||
<extra>::
|
||||
This can be any options that the archiver backend understand.
|
||||
|
||||
--remote=<repo>::
|
||||
Instead of making a tar archive from local repository,
|
||||
retrieve a tar archive from a remote repository.
|
||||
|
||||
<tree-ish>::
|
||||
The tree or commit to produce an archive for.
|
||||
|
||||
path::
|
||||
If one or more paths are specified, include only these in the
|
||||
archive, otherwise include all files and subdirectories.
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
By default, file and directories modes are set to 0666 or 0777 in tar
|
||||
archives. It is possible to change this by setting the "umask" variable
|
||||
in the repository configuration as follows :
|
||||
|
||||
[tar]
|
||||
umask = 002 ;# group friendly
|
||||
|
||||
The special umask value "user" indicates that the user's current umask
|
||||
will be used instead. The default value remains 0, which means world
|
||||
readable/writable files and directories.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
git archive --format=tar --prefix=junk/ HEAD | (cd /var/tmp/ && tar xf -)::
|
||||
|
||||
Create a tar archive that contains the contents of the
|
||||
latest commit on the current branch, and extracts it in
|
||||
`/var/tmp/junk` directory.
|
||||
|
||||
git archive --format=tar --prefix=git-1.4.0/ v1.4.0 | gzip >git-1.4.0.tar.gz::
|
||||
|
||||
Create a compressed tarball for v1.4.0 release.
|
||||
|
||||
git archive --format=tar --prefix=git-1.4.0/ v1.4.0{caret}\{tree\} | gzip >git-1.4.0.tar.gz::
|
||||
|
||||
Create a compressed tarball for v1.4.0 release, but without a
|
||||
global extended pax header.
|
||||
|
||||
git archive --format=zip --prefix=git-docs/ HEAD:Documentation/ > git-1.4.0-docs.zip::
|
||||
|
||||
Put everything in the current head's Documentation/ directory
|
||||
into 'git-1.4.0-docs.zip', with the prefix 'git-docs/'.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Franck Bui-Huu and Rene Scharfe.
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the gitlink:git[7] suite
|
|
@ -0,0 +1,37 @@
|
|||
git-upload-archive(1)
|
||||
====================
|
||||
|
||||
NAME
|
||||
----
|
||||
git-upload-archive - Send archive
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-upload-archive' <directory>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Invoked by 'git-archive --remote' and sends a generated archive to the
|
||||
other end over the git protocol.
|
||||
|
||||
This command is usually not invoked directly by the end user. The UI
|
||||
for the protocol is on the 'git-archive' side, and the program pair
|
||||
is meant to be used to get an archive from a remote repository.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
<directory>::
|
||||
The repository to get a tar archive from.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Franck Bui-Huu.
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the gitlink:git[7] suite
|
8
Makefile
8
Makefile
|
@ -234,8 +234,8 @@ LIB_FILE=libgit.a
|
|||
XDIFF_LIB=xdiff/lib.a
|
||||
|
||||
LIB_H = \
|
||||
blob.h cache.h commit.h csum-file.h delta.h \
|
||||
diff.h object.h pack.h pkt-line.h quote.h refs.h \
|
||||
archive.h blob.h cache.h commit.h csum-file.h delta.h \
|
||||
diff.h object.h pack.h pkt-line.h quote.h refs.h sideband.h \
|
||||
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
|
||||
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h
|
||||
|
||||
|
@ -247,7 +247,7 @@ DIFF_OBJS = \
|
|||
LIB_OBJS = \
|
||||
blob.o commit.o connect.o csum-file.o cache-tree.o base85.o \
|
||||
date.o diff-delta.o entry.o exec_cmd.o ident.o lockfile.o \
|
||||
object.o pack-check.o patch-delta.o path.o pkt-line.o \
|
||||
object.o pack-check.o patch-delta.o path.o pkt-line.o sideband.o \
|
||||
quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
|
||||
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
|
||||
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
|
||||
|
@ -258,6 +258,7 @@ LIB_OBJS = \
|
|||
BUILTIN_OBJS = \
|
||||
builtin-add.o \
|
||||
builtin-apply.o \
|
||||
builtin-archive.o \
|
||||
builtin-cat-file.o \
|
||||
builtin-checkout-index.o \
|
||||
builtin-check-ref-format.o \
|
||||
|
@ -294,6 +295,7 @@ BUILTIN_OBJS = \
|
|||
builtin-unpack-objects.o \
|
||||
builtin-update-index.o \
|
||||
builtin-update-ref.o \
|
||||
builtin-upload-archive.o \
|
||||
builtin-upload-tar.o \
|
||||
builtin-verify-pack.o \
|
||||
builtin-write-tree.o \
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef ARCHIVE_H
|
||||
#define ARCHIVE_H
|
||||
|
||||
#define MAX_EXTRA_ARGS 32
|
||||
#define MAX_ARGS (MAX_EXTRA_ARGS + 32)
|
||||
|
||||
struct archiver_args {
|
||||
const char *base;
|
||||
struct tree *tree;
|
||||
const unsigned char *commit_sha1;
|
||||
time_t time;
|
||||
const char **pathspec;
|
||||
unsigned int verbose : 1;
|
||||
void *extra;
|
||||
};
|
||||
|
||||
typedef int (*write_archive_fn_t)(struct archiver_args *);
|
||||
|
||||
typedef void *(*parse_extra_args_fn_t)(int argc, const char **argv);
|
||||
|
||||
struct archiver {
|
||||
const char *name;
|
||||
struct archiver_args args;
|
||||
write_archive_fn_t write_archive;
|
||||
parse_extra_args_fn_t parse_extra;
|
||||
};
|
||||
|
||||
extern struct archiver archivers[];
|
||||
|
||||
extern int parse_archive_args(int argc,
|
||||
const char **argv,
|
||||
struct archiver *ar);
|
||||
|
||||
extern void parse_treeish_arg(const char **treeish,
|
||||
struct archiver_args *ar_args,
|
||||
const char *prefix);
|
||||
|
||||
extern void parse_pathspec_arg(const char **pathspec,
|
||||
struct archiver_args *args);
|
||||
/*
|
||||
* Archive-format specific backends.
|
||||
*/
|
||||
extern int write_tar_archive(struct archiver_args *);
|
||||
extern int write_zip_archive(struct archiver_args *);
|
||||
extern void *parse_extra_zip_args(int argc, const char **argv);
|
||||
|
||||
#endif /* ARCHIVE_H */
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* Copyright (c) 2006 Franck Bui-Huu
|
||||
* Copyright (c) 2006 Rene Scharfe
|
||||
*/
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "archive.h"
|
||||
#include "commit.h"
|
||||
#include "tree-walk.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "pkt-line.h"
|
||||
#include "sideband.h"
|
||||
|
||||
static const char archive_usage[] = \
|
||||
"git-archive --format=<fmt> [--prefix=<prefix>/] [--verbose] [<extra>] <tree-ish> [path...]";
|
||||
|
||||
struct archiver archivers[] = {
|
||||
{
|
||||
.name = "tar",
|
||||
.write_archive = write_tar_archive,
|
||||
},
|
||||
{
|
||||
.name = "zip",
|
||||
.write_archive = write_zip_archive,
|
||||
.parse_extra = parse_extra_zip_args,
|
||||
},
|
||||
};
|
||||
|
||||
static int run_remote_archiver(const char *remote, int argc,
|
||||
const char **argv)
|
||||
{
|
||||
char *url, buf[LARGE_PACKET_MAX];
|
||||
int fd[2], i, len, rv;
|
||||
pid_t pid;
|
||||
const char *exec = "git-upload-archive";
|
||||
int exec_at = 0;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strncmp("--exec=", arg, 7)) {
|
||||
if (exec_at)
|
||||
die("multiple --exec specified");
|
||||
exec = arg + 7;
|
||||
exec_at = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
url = xstrdup(remote);
|
||||
pid = git_connect(fd, url, exec);
|
||||
if (pid < 0)
|
||||
return pid;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (i == exec_at)
|
||||
continue;
|
||||
packet_write(fd[1], "argument %s\n", argv[i]);
|
||||
}
|
||||
packet_flush(fd[1]);
|
||||
|
||||
len = packet_read_line(fd[0], buf, sizeof(buf));
|
||||
if (!len)
|
||||
die("git-archive: expected ACK/NAK, got EOF");
|
||||
if (buf[len-1] == '\n')
|
||||
buf[--len] = 0;
|
||||
if (strcmp(buf, "ACK")) {
|
||||
if (len > 5 && !strncmp(buf, "NACK ", 5))
|
||||
die("git-archive: NACK %s", buf + 5);
|
||||
die("git-archive: protocol error");
|
||||
}
|
||||
|
||||
len = packet_read_line(fd[0], buf, sizeof(buf));
|
||||
if (len)
|
||||
die("git-archive: expected a flush");
|
||||
|
||||
/* Now, start reading from fd[0] and spit it out to stdout */
|
||||
rv = recv_sideband("archive", fd[0], 1, 2, buf, sizeof(buf));
|
||||
close(fd[0]);
|
||||
rv |= finish_connect(pid);
|
||||
|
||||
return !!rv;
|
||||
}
|
||||
|
||||
static int init_archiver(const char *name, struct archiver *ar)
|
||||
{
|
||||
int rv = -1, i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(archivers); i++) {
|
||||
if (!strcmp(name, archivers[i].name)) {
|
||||
memcpy(ar, &archivers[i], sizeof(struct archiver));
|
||||
rv = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void parse_pathspec_arg(const char **pathspec, struct archiver_args *ar_args)
|
||||
{
|
||||
ar_args->pathspec = get_pathspec(ar_args->base, pathspec);
|
||||
}
|
||||
|
||||
void parse_treeish_arg(const char **argv, struct archiver_args *ar_args,
|
||||
const char *prefix)
|
||||
{
|
||||
const char *name = argv[0];
|
||||
const unsigned char *commit_sha1;
|
||||
time_t archive_time;
|
||||
struct tree *tree;
|
||||
struct commit *commit;
|
||||
unsigned char sha1[20];
|
||||
|
||||
if (get_sha1(name, sha1))
|
||||
die("Not a valid object name");
|
||||
|
||||
commit = lookup_commit_reference_gently(sha1, 1);
|
||||
if (commit) {
|
||||
commit_sha1 = commit->object.sha1;
|
||||
archive_time = commit->date;
|
||||
} else {
|
||||
commit_sha1 = NULL;
|
||||
archive_time = time(NULL);
|
||||
}
|
||||
|
||||
tree = parse_tree_indirect(sha1);
|
||||
if (tree == NULL)
|
||||
die("not a tree object");
|
||||
|
||||
if (prefix) {
|
||||
unsigned char tree_sha1[20];
|
||||
unsigned int mode;
|
||||
int err;
|
||||
|
||||
err = get_tree_entry(tree->object.sha1, prefix,
|
||||
tree_sha1, &mode);
|
||||
if (err || !S_ISDIR(mode))
|
||||
die("current working directory is untracked");
|
||||
|
||||
free(tree);
|
||||
tree = parse_tree_indirect(tree_sha1);
|
||||
}
|
||||
ar_args->tree = tree;
|
||||
ar_args->commit_sha1 = commit_sha1;
|
||||
ar_args->time = archive_time;
|
||||
}
|
||||
|
||||
int parse_archive_args(int argc, const char **argv, struct archiver *ar)
|
||||
{
|
||||
const char *extra_argv[MAX_EXTRA_ARGS];
|
||||
int extra_argc = 0;
|
||||
const char *format = NULL; /* might want to default to "tar" */
|
||||
const char *base = "";
|
||||
int verbose = 0;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
if (!strcmp(arg, "--list") || !strcmp(arg, "-l")) {
|
||||
for (i = 0; i < ARRAY_SIZE(archivers); i++)
|
||||
printf("%s\n", archivers[i].name);
|
||||
exit(0);
|
||||
}
|
||||
if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) {
|
||||
verbose = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--format=", 9)) {
|
||||
format = arg + 9;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--prefix=", 9)) {
|
||||
base = arg + 9;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--")) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (arg[0] == '-') {
|
||||
if (extra_argc > MAX_EXTRA_ARGS - 1)
|
||||
die("Too many extra options");
|
||||
extra_argv[extra_argc++] = arg;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* We need at least one parameter -- tree-ish */
|
||||
if (argc - 1 < i)
|
||||
usage(archive_usage);
|
||||
if (!format)
|
||||
die("You must specify an archive format");
|
||||
if (init_archiver(format, ar) < 0)
|
||||
die("Unknown archive format '%s'", format);
|
||||
|
||||
if (extra_argc) {
|
||||
if (!ar->parse_extra)
|
||||
die("'%s' format does not handle %s",
|
||||
ar->name, extra_argv[0]);
|
||||
ar->args.extra = ar->parse_extra(extra_argc, extra_argv);
|
||||
}
|
||||
ar->args.verbose = verbose;
|
||||
ar->args.base = base;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static const char *extract_remote_arg(int *ac, const char **av)
|
||||
{
|
||||
int ix, iy, cnt = *ac;
|
||||
int no_more_options = 0;
|
||||
const char *remote = NULL;
|
||||
|
||||
for (ix = iy = 1; ix < cnt; ix++) {
|
||||
const char *arg = av[ix];
|
||||
if (!strcmp(arg, "--"))
|
||||
no_more_options = 1;
|
||||
if (!no_more_options) {
|
||||
if (!strncmp(arg, "--remote=", 9)) {
|
||||
if (remote)
|
||||
die("Multiple --remote specified");
|
||||
remote = arg + 9;
|
||||
continue;
|
||||
}
|
||||
if (arg[0] != '-')
|
||||
no_more_options = 1;
|
||||
}
|
||||
if (ix != iy)
|
||||
av[iy] = arg;
|
||||
iy++;
|
||||
}
|
||||
if (remote) {
|
||||
av[--cnt] = NULL;
|
||||
*ac = cnt;
|
||||
}
|
||||
return remote;
|
||||
}
|
||||
|
||||
int cmd_archive(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct archiver ar;
|
||||
int tree_idx;
|
||||
const char *remote = NULL;
|
||||
|
||||
remote = extract_remote_arg(&argc, argv);
|
||||
if (remote)
|
||||
return run_remote_archiver(remote, argc, argv);
|
||||
|
||||
setlinebuf(stderr);
|
||||
|
||||
memset(&ar, 0, sizeof(ar));
|
||||
tree_idx = parse_archive_args(argc, argv, &ar);
|
||||
if (prefix == NULL)
|
||||
prefix = setup_git_directory();
|
||||
|
||||
argv += tree_idx;
|
||||
parse_treeish_arg(argv, &ar.args, prefix);
|
||||
parse_pathspec_arg(argv + 1, &ar.args);
|
||||
|
||||
return ar.write_archive(&ar.args);
|
||||
}
|
|
@ -3,12 +3,12 @@
|
|||
*/
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "tree-walk.h"
|
||||
#include "commit.h"
|
||||
#include "strbuf.h"
|
||||
#include "tar.h"
|
||||
#include "builtin.h"
|
||||
#include "pkt-line.h"
|
||||
#include "archive.h"
|
||||
|
||||
#define RECORDSIZE (512)
|
||||
#define BLOCKSIZE (RECORDSIZE * 20)
|
||||
|
@ -21,6 +21,7 @@ static unsigned long offset;
|
|||
|
||||
static time_t archive_time;
|
||||
static int tar_umask;
|
||||
static int verbose;
|
||||
|
||||
/* writes out the whole block, but only if it is full */
|
||||
static void write_if_needed(void)
|
||||
|
@ -168,6 +169,8 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
|
|||
mode = 0100666;
|
||||
sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
|
||||
} else {
|
||||
if (verbose)
|
||||
fprintf(stderr, "%.*s\n", path->len, path->buf);
|
||||
if (S_ISDIR(mode)) {
|
||||
*header.typeflag = TYPEFLAG_DIR;
|
||||
mode = (mode | 0777) & ~tar_umask;
|
||||
|
@ -244,37 +247,6 @@ static void write_global_extended_header(const unsigned char *sha1)
|
|||
free(ext_header.buf);
|
||||
}
|
||||
|
||||
static void traverse_tree(struct tree_desc *tree, struct strbuf *path)
|
||||
{
|
||||
int pathlen = path->len;
|
||||
struct name_entry entry;
|
||||
|
||||
while (tree_entry(tree, &entry)) {
|
||||
void *eltbuf;
|
||||
char elttype[20];
|
||||
unsigned long eltsize;
|
||||
|
||||
eltbuf = read_sha1_file(entry.sha1, elttype, &eltsize);
|
||||
if (!eltbuf)
|
||||
die("cannot read %s", sha1_to_hex(entry.sha1));
|
||||
|
||||
path->len = pathlen;
|
||||
strbuf_append_string(path, entry.path);
|
||||
if (S_ISDIR(entry.mode))
|
||||
strbuf_append_string(path, "/");
|
||||
|
||||
write_entry(entry.sha1, path, entry.mode, eltbuf, eltsize);
|
||||
|
||||
if (S_ISDIR(entry.mode)) {
|
||||
struct tree_desc subtree;
|
||||
subtree.buf = eltbuf;
|
||||
subtree.size = eltsize;
|
||||
traverse_tree(&subtree, path);
|
||||
}
|
||||
free(eltbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static int git_tar_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "tar.umask")) {
|
||||
|
@ -291,50 +263,95 @@ static int git_tar_config(const char *var, const char *value)
|
|||
|
||||
static int generate_tar(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
unsigned char sha1[20], tree_sha1[20];
|
||||
struct commit *commit;
|
||||
struct tree_desc tree;
|
||||
struct strbuf current_path;
|
||||
void *buffer;
|
||||
|
||||
current_path.buf = xmalloc(PATH_MAX);
|
||||
current_path.alloc = PATH_MAX;
|
||||
current_path.len = current_path.eof = 0;
|
||||
struct archiver_args args;
|
||||
int result;
|
||||
char *base = NULL;
|
||||
|
||||
git_config(git_tar_config);
|
||||
|
||||
switch (argc) {
|
||||
case 3:
|
||||
strbuf_append_string(¤t_path, argv[2]);
|
||||
strbuf_append_string(¤t_path, "/");
|
||||
/* FALLTHROUGH */
|
||||
case 2:
|
||||
if (get_sha1(argv[1], sha1))
|
||||
die("Not a valid object name %s", argv[1]);
|
||||
break;
|
||||
default:
|
||||
memset(&args, 0, sizeof(args));
|
||||
if (argc != 2 && argc != 3)
|
||||
usage(tar_tree_usage);
|
||||
if (argc == 3) {
|
||||
int baselen = strlen(argv[2]);
|
||||
base = xmalloc(baselen + 2);
|
||||
memcpy(base, argv[2], baselen);
|
||||
base[baselen] = '/';
|
||||
base[baselen + 1] = '\0';
|
||||
}
|
||||
args.base = base;
|
||||
parse_treeish_arg(argv + 1, &args, NULL);
|
||||
|
||||
result = write_tar_archive(&args);
|
||||
free(base);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int write_tar_entry(const unsigned char *sha1,
|
||||
const char *base, int baselen,
|
||||
const char *filename, unsigned mode, int stage)
|
||||
{
|
||||
static struct strbuf path;
|
||||
int filenamelen = strlen(filename);
|
||||
void *buffer;
|
||||
char type[20];
|
||||
unsigned long size;
|
||||
|
||||
if (!path.alloc) {
|
||||
path.buf = xmalloc(PATH_MAX);
|
||||
path.alloc = PATH_MAX;
|
||||
path.len = path.eof = 0;
|
||||
}
|
||||
if (path.alloc < baselen + filenamelen) {
|
||||
free(path.buf);
|
||||
path.buf = xmalloc(baselen + filenamelen);
|
||||
path.alloc = baselen + filenamelen;
|
||||
}
|
||||
memcpy(path.buf, base, baselen);
|
||||
memcpy(path.buf + baselen, filename, filenamelen);
|
||||
path.len = baselen + filenamelen;
|
||||
if (S_ISDIR(mode)) {
|
||||
strbuf_append_string(&path, "/");
|
||||
buffer = NULL;
|
||||
size = 0;
|
||||
} else {
|
||||
buffer = read_sha1_file(sha1, type, &size);
|
||||
if (!buffer)
|
||||
die("cannot read %s", sha1_to_hex(sha1));
|
||||
}
|
||||
|
||||
commit = lookup_commit_reference_gently(sha1, 1);
|
||||
if (commit) {
|
||||
write_global_extended_header(commit->object.sha1);
|
||||
archive_time = commit->date;
|
||||
} else
|
||||
archive_time = time(NULL);
|
||||
|
||||
tree.buf = buffer = read_object_with_reference(sha1, tree_type,
|
||||
&tree.size, tree_sha1);
|
||||
if (!tree.buf)
|
||||
die("not a reference to a tag, commit or tree object: %s",
|
||||
sha1_to_hex(sha1));
|
||||
|
||||
if (current_path.len > 0)
|
||||
write_entry(tree_sha1, ¤t_path, 040777, NULL, 0);
|
||||
traverse_tree(&tree, ¤t_path);
|
||||
write_trailer();
|
||||
write_entry(sha1, &path, mode, buffer, size);
|
||||
free(buffer);
|
||||
free(current_path.buf);
|
||||
|
||||
return READ_TREE_RECURSIVE;
|
||||
}
|
||||
|
||||
int write_tar_archive(struct archiver_args *args)
|
||||
{
|
||||
int plen = args->base ? strlen(args->base) : 0;
|
||||
|
||||
git_config(git_tar_config);
|
||||
|
||||
archive_time = args->time;
|
||||
verbose = args->verbose;
|
||||
|
||||
if (args->commit_sha1)
|
||||
write_global_extended_header(args->commit_sha1);
|
||||
|
||||
if (args->base && plen > 0 && args->base[plen - 1] == '/') {
|
||||
char *base = xstrdup(args->base);
|
||||
int baselen = strlen(base);
|
||||
|
||||
while (baselen > 0 && base[baselen - 1] == '/')
|
||||
base[--baselen] = '\0';
|
||||
write_tar_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
|
||||
free(base);
|
||||
}
|
||||
read_tree_recursive(args->tree, args->base, plen, 0,
|
||||
args->pathspec, write_tar_entry);
|
||||
write_trailer();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright (c) 2006 Franck Bui-Huu
|
||||
*/
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "archive.h"
|
||||
#include "pkt-line.h"
|
||||
#include "sideband.h"
|
||||
#include <sys/wait.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
static const char upload_archive_usage[] =
|
||||
"git-upload-archive <repo>";
|
||||
|
||||
static const char deadchild[] =
|
||||
"git-upload-archive: archiver died with error";
|
||||
|
||||
static const char lostchild[] =
|
||||
"git-upload-archive: archiver process was lost";
|
||||
|
||||
|
||||
static int run_upload_archive(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct archiver ar;
|
||||
const char *sent_argv[MAX_ARGS];
|
||||
const char *arg_cmd = "argument ";
|
||||
char *p, buf[4096];
|
||||
int treeish_idx;
|
||||
int sent_argc;
|
||||
int len;
|
||||
|
||||
if (argc != 2)
|
||||
usage(upload_archive_usage);
|
||||
|
||||
if (strlen(argv[1]) > sizeof(buf))
|
||||
die("insanely long repository name");
|
||||
|
||||
strcpy(buf, argv[1]); /* enter-repo smudges its argument */
|
||||
|
||||
if (!enter_repo(buf, 0))
|
||||
die("not a git archive");
|
||||
|
||||
/* put received options in sent_argv[] */
|
||||
sent_argc = 1;
|
||||
sent_argv[0] = "git-upload-archive";
|
||||
for (p = buf;;) {
|
||||
/* This will die if not enough free space in buf */
|
||||
len = packet_read_line(0, p, (buf + sizeof buf) - p);
|
||||
if (len == 0)
|
||||
break; /* got a flush */
|
||||
if (sent_argc > MAX_ARGS - 2)
|
||||
die("Too many options (>29)");
|
||||
|
||||
if (p[len-1] == '\n') {
|
||||
p[--len] = 0;
|
||||
}
|
||||
if (len < strlen(arg_cmd) ||
|
||||
strncmp(arg_cmd, p, strlen(arg_cmd)))
|
||||
die("'argument' token or flush expected");
|
||||
|
||||
len -= strlen(arg_cmd);
|
||||
memmove(p, p + strlen(arg_cmd), len);
|
||||
sent_argv[sent_argc++] = p;
|
||||
p += len;
|
||||
*p++ = 0;
|
||||
}
|
||||
sent_argv[sent_argc] = NULL;
|
||||
|
||||
/* parse all options sent by the client */
|
||||
treeish_idx = parse_archive_args(sent_argc, sent_argv, &ar);
|
||||
|
||||
parse_treeish_arg(sent_argv + treeish_idx, &ar.args, prefix);
|
||||
parse_pathspec_arg(sent_argv + treeish_idx + 1, &ar.args);
|
||||
|
||||
return ar.write_archive(&ar.args);
|
||||
}
|
||||
|
||||
static void error_clnt(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
va_list params;
|
||||
int len;
|
||||
|
||||
va_start(params, fmt);
|
||||
len = vsprintf(buf, fmt, params);
|
||||
va_end(params);
|
||||
send_sideband(1, 3, buf, len, LARGE_PACKET_MAX);
|
||||
die("sent error to the client: %s", buf);
|
||||
}
|
||||
|
||||
static void process_input(int child_fd, int band)
|
||||
{
|
||||
char buf[16384];
|
||||
ssize_t sz = read(child_fd, buf, sizeof(buf));
|
||||
if (sz < 0) {
|
||||
if (errno != EINTR)
|
||||
error_clnt("read error: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
send_sideband(1, band, buf, sz, LARGE_PACKET_MAX);
|
||||
}
|
||||
|
||||
int cmd_upload_archive(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
pid_t writer;
|
||||
int fd1[2], fd2[2];
|
||||
/*
|
||||
* Set up sideband subprocess.
|
||||
*
|
||||
* We (parent) monitor and read from child, sending its fd#1 and fd#2
|
||||
* multiplexed out to our fd#1. If the child dies, we tell the other
|
||||
* end over channel #3.
|
||||
*/
|
||||
if (pipe(fd1) < 0 || pipe(fd2) < 0) {
|
||||
int err = errno;
|
||||
packet_write(1, "NACK pipe failed on the remote side\n");
|
||||
die("upload-archive: %s", strerror(err));
|
||||
}
|
||||
writer = fork();
|
||||
if (writer < 0) {
|
||||
int err = errno;
|
||||
packet_write(1, "NACK fork failed on the remote side\n");
|
||||
die("upload-archive: %s", strerror(err));
|
||||
}
|
||||
if (!writer) {
|
||||
/* child - connect fd#1 and fd#2 to the pipe */
|
||||
dup2(fd1[1], 1);
|
||||
dup2(fd2[1], 2);
|
||||
close(fd1[1]); close(fd2[1]);
|
||||
close(fd1[0]); close(fd2[0]); /* we do not read from pipe */
|
||||
|
||||
exit(run_upload_archive(argc, argv, prefix));
|
||||
}
|
||||
|
||||
/* parent - read from child, multiplex and send out to fd#1 */
|
||||
close(fd1[1]); close(fd2[1]); /* we do not write to pipe */
|
||||
packet_write(1, "ACK\n");
|
||||
packet_flush(1);
|
||||
|
||||
while (1) {
|
||||
struct pollfd pfd[2];
|
||||
int status;
|
||||
|
||||
pfd[0].fd = fd1[0];
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[1].fd = fd2[0];
|
||||
pfd[1].events = POLLIN;
|
||||
if (poll(pfd, 2, -1) < 0) {
|
||||
if (errno != EINTR) {
|
||||
error("poll failed resuming: %s",
|
||||
strerror(errno));
|
||||
sleep(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (pfd[0].revents & POLLIN)
|
||||
/* Data stream ready */
|
||||
process_input(pfd[0].fd, 1);
|
||||
if (pfd[1].revents & POLLIN)
|
||||
/* Status stream ready */
|
||||
process_input(pfd[1].fd, 2);
|
||||
if ((pfd[0].revents | pfd[1].revents) == POLLIN)
|
||||
continue;
|
||||
|
||||
if (waitpid(writer, &status, 0) < 0)
|
||||
error_clnt("%s", lostchild);
|
||||
else if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
|
||||
error_clnt("%s", deadchild);
|
||||
packet_flush(1);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -8,10 +8,12 @@
|
|||
#include "tree.h"
|
||||
#include "quote.h"
|
||||
#include "builtin.h"
|
||||
#include "archive.h"
|
||||
|
||||
static const char zip_tree_usage[] =
|
||||
"git-zip-tree [-0|...|-9] <tree-ish> [ <base> ]";
|
||||
|
||||
static int verbose;
|
||||
static int zip_date;
|
||||
static int zip_time;
|
||||
|
||||
|
@ -163,6 +165,8 @@ static int write_zip_entry(const unsigned char *sha1,
|
|||
crc = crc32(0, Z_NULL, 0);
|
||||
|
||||
path = construct_path(base, baselen, filename, S_ISDIR(mode), &pathlen);
|
||||
if (verbose)
|
||||
fprintf(stderr, "%s\n", path);
|
||||
if (pathlen > 0xffff) {
|
||||
error("path too long (%d chars, SHA1: %s): %s", pathlen,
|
||||
sha1_to_hex(sha1), path);
|
||||
|
@ -351,3 +355,44 @@ int cmd_zip_tree(int argc, const char **argv, const char *prefix)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_zip_archive(struct archiver_args *args)
|
||||
{
|
||||
int plen = strlen(args->base);
|
||||
|
||||
dos_time(&args->time, &zip_date, &zip_time);
|
||||
|
||||
zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
|
||||
zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
|
||||
verbose = args->verbose;
|
||||
|
||||
if (args->base && plen > 0 && args->base[plen - 1] == '/') {
|
||||
char *base = xstrdup(args->base);
|
||||
int baselen = strlen(base);
|
||||
|
||||
while (baselen > 0 && base[baselen - 1] == '/')
|
||||
base[--baselen] = '\0';
|
||||
write_zip_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
|
||||
free(base);
|
||||
}
|
||||
read_tree_recursive(args->tree, args->base, plen, 0,
|
||||
args->pathspec, write_zip_entry);
|
||||
write_zip_trailer(args->commit_sha1);
|
||||
|
||||
free(zip_dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *parse_extra_zip_args(int argc, const char **argv)
|
||||
{
|
||||
for (; argc > 0; argc--, argv++) {
|
||||
const char *arg = argv[0];
|
||||
|
||||
if (arg[0] == '-' && isdigit(arg[1]) && arg[2] == '\0')
|
||||
zlib_compression_level = arg[1] - '0';
|
||||
else
|
||||
die("Unknown argument for zip format: %s", arg);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
|
|||
|
||||
extern int cmd_add(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_apply(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_archive(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
|
||||
|
@ -55,6 +56,7 @@ extern int cmd_zip_tree(int argc, const char **argv, const char *prefix);
|
|||
extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_update_index(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_upload_archive(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_version(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
|
||||
|
|
7
daemon.c
7
daemon.c
|
@ -325,7 +325,14 @@ static int upload_pack(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int upload_archive(void)
|
||||
{
|
||||
execl_git_cmd("upload-archive", ".", NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct daemon_service daemon_service[] = {
|
||||
{ "upload-archive", "uploadarch", upload_archive, 0, 1 },
|
||||
{ "upload-pack", "uploadpack", upload_pack, 1, 1 },
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "cache.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "pkt-line.h"
|
||||
#include "sideband.h"
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
|
@ -114,36 +115,13 @@ static pid_t setup_sideband(int sideband, const char *me, int fd[2], int xd[2])
|
|||
die("%s: unable to fork off sideband demultiplexer", me);
|
||||
if (!side_pid) {
|
||||
/* subprocess */
|
||||
char buf[LARGE_PACKET_MAX];
|
||||
|
||||
close(fd[0]);
|
||||
if (xd[0] != xd[1])
|
||||
close(xd[1]);
|
||||
while (1) {
|
||||
char buf[1024];
|
||||
int len = packet_read_line(xd[0], buf, sizeof(buf));
|
||||
if (len == 0)
|
||||
break;
|
||||
if (len < 1)
|
||||
die("%s: protocol error: no band designator",
|
||||
me);
|
||||
len--;
|
||||
switch (buf[0] & 0xFF) {
|
||||
case 3:
|
||||
safe_write(2, "remote: ", 8);
|
||||
safe_write(2, buf+1, len);
|
||||
safe_write(2, "\n", 1);
|
||||
exit(1);
|
||||
case 2:
|
||||
safe_write(2, "remote: ", 8);
|
||||
safe_write(2, buf+1, len);
|
||||
continue;
|
||||
case 1:
|
||||
safe_write(fd[1], buf+1, len);
|
||||
continue;
|
||||
default:
|
||||
die("%s: protocol error: bad band #%d",
|
||||
me, (buf[0] & 0xFF));
|
||||
}
|
||||
}
|
||||
if (recv_sideband(me, xd[0], fd[1], 2, buf, sizeof(buf)))
|
||||
exit(1);
|
||||
exit(0);
|
||||
}
|
||||
close(xd[0]);
|
||||
|
|
12
fetch-pack.c
12
fetch-pack.c
|
@ -166,10 +166,11 @@ static int find_common(int fd[2], unsigned char *result_sha1,
|
|||
}
|
||||
|
||||
if (!fetching)
|
||||
packet_write(fd[1], "want %s%s%s%s\n",
|
||||
packet_write(fd[1], "want %s%s%s%s%s\n",
|
||||
sha1_to_hex(remote),
|
||||
(multi_ack ? " multi_ack" : ""),
|
||||
(use_sideband ? " side-band" : ""),
|
||||
(use_sideband == 2 ? " side-band-64k" : ""),
|
||||
(use_sideband == 1 ? " side-band" : ""),
|
||||
(use_thin_pack ? " thin-pack" : ""));
|
||||
else
|
||||
packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
|
||||
|
@ -426,7 +427,12 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
|
|||
fprintf(stderr, "Server supports multi_ack\n");
|
||||
multi_ack = 1;
|
||||
}
|
||||
if (server_supports("side-band")) {
|
||||
if (server_supports("side-band-64k")) {
|
||||
if (verbose)
|
||||
fprintf(stderr, "Server supports side-band-64k\n");
|
||||
use_sideband = 2;
|
||||
}
|
||||
else if (server_supports("side-band")) {
|
||||
if (verbose)
|
||||
fprintf(stderr, "Server supports side-band\n");
|
||||
use_sideband = 1;
|
||||
|
|
|
@ -12,6 +12,7 @@ struct cmdname_help common_cmds[] = {"
|
|||
sort <<\EOF |
|
||||
add
|
||||
apply
|
||||
archive
|
||||
bisect
|
||||
branch
|
||||
checkout
|
||||
|
|
2
git.c
2
git.c
|
@ -220,6 +220,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
|||
} commands[] = {
|
||||
{ "add", cmd_add, RUN_SETUP },
|
||||
{ "apply", cmd_apply },
|
||||
{ "archive", cmd_archive },
|
||||
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
||||
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
||||
{ "check-ref-format", cmd_check_ref_format },
|
||||
|
@ -261,6 +262,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
|||
{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
|
||||
{ "update-index", cmd_update_index, RUN_SETUP },
|
||||
{ "update-ref", cmd_update_ref, RUN_SETUP },
|
||||
{ "upload-archive", cmd_upload_archive },
|
||||
{ "upload-tar", cmd_upload_tar },
|
||||
{ "version", cmd_version },
|
||||
{ "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#include "pkt-line.h"
|
||||
#include "sideband.h"
|
||||
|
||||
/*
|
||||
* Receive multiplexed output stream over git native protocol.
|
||||
* in_stream is the input stream from the remote, which carries data
|
||||
* in pkt_line format with band designator. Demultiplex it into out
|
||||
* and err and return error appropriately. Band #1 carries the
|
||||
* primary payload. Things coming over band #2 is not necessarily
|
||||
* error; they are usually informative message on the standard error
|
||||
* stream, aka "verbose"). A message over band #3 is a signal that
|
||||
* the remote died unexpectedly. A flush() concludes the stream.
|
||||
*/
|
||||
int recv_sideband(const char *me, int in_stream, int out, int err, char *buf, int bufsz)
|
||||
{
|
||||
while (1) {
|
||||
int len = packet_read_line(in_stream, buf, bufsz);
|
||||
if (len == 0)
|
||||
break;
|
||||
if (len < 1) {
|
||||
len = sprintf(buf, "%s: protocol error: no band designator\n", me);
|
||||
safe_write(err, buf, len);
|
||||
return SIDEBAND_PROTOCOL_ERROR;
|
||||
}
|
||||
len--;
|
||||
switch (buf[0] & 0xFF) {
|
||||
case 3:
|
||||
safe_write(err, "remote: ", 8);
|
||||
safe_write(err, buf+1, len);
|
||||
safe_write(err, "\n", 1);
|
||||
return SIDEBAND_REMOTE_ERROR;
|
||||
case 2:
|
||||
safe_write(err, "remote: ", 8);
|
||||
safe_write(err, buf+1, len);
|
||||
continue;
|
||||
case 1:
|
||||
safe_write(out, buf+1, len);
|
||||
continue;
|
||||
default:
|
||||
len = sprintf(buf + 1,
|
||||
"%s: protocol error: bad band #%d\n",
|
||||
me, buf[0] & 0xFF);
|
||||
safe_write(err, buf+1, len);
|
||||
return SIDEBAND_PROTOCOL_ERROR;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fd is connected to the remote side; send the sideband data
|
||||
* over multiplexed packet stream.
|
||||
*/
|
||||
ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max)
|
||||
{
|
||||
ssize_t ssz = sz;
|
||||
const char *p = data;
|
||||
|
||||
while (sz) {
|
||||
unsigned n;
|
||||
char hdr[5];
|
||||
|
||||
n = sz;
|
||||
if (packet_max - 5 < n)
|
||||
n = packet_max - 5;
|
||||
sprintf(hdr, "%04x", n + 5);
|
||||
hdr[4] = band;
|
||||
safe_write(fd, hdr, 5);
|
||||
safe_write(fd, p, n);
|
||||
p += n;
|
||||
sz -= n;
|
||||
}
|
||||
return ssz;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef SIDEBAND_H
|
||||
#define SIDEBAND_H
|
||||
|
||||
#define SIDEBAND_PROTOCOL_ERROR -2
|
||||
#define SIDEBAND_REMOTE_ERROR -1
|
||||
|
||||
#define DEFAULT_PACKET_MAX 1000
|
||||
#define LARGE_PACKET_MAX 65520
|
||||
|
||||
int recv_sideband(const char *me, int in_stream, int out, int err, char *, int);
|
||||
ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max);
|
||||
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "pkt-line.h"
|
||||
#include "sideband.h"
|
||||
#include "tag.h"
|
||||
#include "object.h"
|
||||
#include "commit.h"
|
||||
|
@ -19,6 +20,9 @@ static int use_thin_pack;
|
|||
static struct object_array have_obj;
|
||||
static struct object_array want_obj;
|
||||
static unsigned int timeout;
|
||||
/* 0 for no sideband,
|
||||
* otherwise maximum packet size (up to 65520 bytes).
|
||||
*/
|
||||
static int use_sideband;
|
||||
|
||||
static void reset_timeout(void)
|
||||
|
@ -33,45 +37,18 @@ static int strip(char *line, int len)
|
|||
return len;
|
||||
}
|
||||
|
||||
#define PACKET_MAX 1000
|
||||
static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
|
||||
{
|
||||
ssize_t ssz;
|
||||
const char *p;
|
||||
|
||||
if (!data) {
|
||||
if (!use_sideband)
|
||||
return 0;
|
||||
packet_flush(1);
|
||||
if (use_sideband)
|
||||
return send_sideband(1, fd, data, sz, use_sideband);
|
||||
if (fd == 3)
|
||||
/* emergency quit */
|
||||
fd = 2;
|
||||
if (fd == 2) {
|
||||
xwrite(fd, data, sz);
|
||||
return sz;
|
||||
}
|
||||
|
||||
if (!use_sideband) {
|
||||
if (fd == 3)
|
||||
/* emergency quit */
|
||||
fd = 2;
|
||||
if (fd == 2) {
|
||||
xwrite(fd, data, sz);
|
||||
return sz;
|
||||
}
|
||||
return safe_write(fd, data, sz);
|
||||
}
|
||||
p = data;
|
||||
ssz = sz;
|
||||
while (sz) {
|
||||
unsigned n;
|
||||
char hdr[5];
|
||||
|
||||
n = sz;
|
||||
if (PACKET_MAX - 5 < n)
|
||||
n = PACKET_MAX - 5;
|
||||
sprintf(hdr, "%04x", n + 5);
|
||||
hdr[4] = fd;
|
||||
safe_write(1, hdr, 5);
|
||||
safe_write(1, p, n);
|
||||
p += n;
|
||||
sz -= n;
|
||||
}
|
||||
return ssz;
|
||||
return safe_write(fd, data, sz);
|
||||
}
|
||||
|
||||
static void create_pack_file(void)
|
||||
|
@ -308,7 +285,8 @@ static void create_pack_file(void)
|
|||
goto fail;
|
||||
fprintf(stderr, "flushed.\n");
|
||||
}
|
||||
send_client_data(1, NULL, 0);
|
||||
if (use_sideband)
|
||||
packet_flush(1);
|
||||
return;
|
||||
}
|
||||
fail:
|
||||
|
@ -413,8 +391,10 @@ static void receive_needs(void)
|
|||
multi_ack = 1;
|
||||
if (strstr(line+45, "thin-pack"))
|
||||
use_thin_pack = 1;
|
||||
if (strstr(line+45, "side-band"))
|
||||
use_sideband = 1;
|
||||
if (strstr(line+45, "side-band-64k"))
|
||||
use_sideband = LARGE_PACKET_MAX;
|
||||
else if (strstr(line+45, "side-band"))
|
||||
use_sideband = DEFAULT_PACKET_MAX;
|
||||
|
||||
/* We have sent all our refs already, and the other end
|
||||
* should have chosen out of them; otherwise they are
|
||||
|
@ -436,7 +416,7 @@ static void receive_needs(void)
|
|||
|
||||
static int send_ref(const char *refname, const unsigned char *sha1)
|
||||
{
|
||||
static const char *capabilities = "multi_ack thin-pack side-band";
|
||||
static const char *capabilities = "multi_ack thin-pack side-band side-band-64k";
|
||||
struct object *o = parse_object(sha1);
|
||||
|
||||
if (!o)
|
||||
|
|
Загрузка…
Ссылка в новой задаче