archive: delegate blob reading to backend
archive-tar.c and archive-zip.c now perform conversion check, with help of sha1_file_to_archive() from archive.c This gives backends more freedom in dealing with (streaming) large blobs. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
853907097a
commit
9cb513b798
@ -161,11 +161,15 @@ static int write_extended_header(struct archiver_args *args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int write_tar_entry(struct archiver_args *args,
|
static int write_tar_entry(struct archiver_args *args,
|
||||||
const unsigned char *sha1, const char *path, size_t pathlen,
|
const unsigned char *sha1,
|
||||||
unsigned int mode, void *buffer, unsigned long size)
|
const char *path, size_t pathlen,
|
||||||
|
unsigned int mode)
|
||||||
{
|
{
|
||||||
struct ustar_header header;
|
struct ustar_header header;
|
||||||
struct strbuf ext_header = STRBUF_INIT;
|
struct strbuf ext_header = STRBUF_INIT;
|
||||||
|
unsigned int old_mode = mode;
|
||||||
|
unsigned long size;
|
||||||
|
void *buffer;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
memset(&header, 0, sizeof(header));
|
memset(&header, 0, sizeof(header));
|
||||||
@ -199,7 +203,17 @@ static int write_tar_entry(struct archiver_args *args,
|
|||||||
} else
|
} else
|
||||||
memcpy(header.name, path, pathlen);
|
memcpy(header.name, path, pathlen);
|
||||||
|
|
||||||
if (S_ISLNK(mode) && buffer) {
|
if (S_ISLNK(mode) || S_ISREG(mode)) {
|
||||||
|
enum object_type type;
|
||||||
|
buffer = sha1_file_to_archive(args, path, sha1, old_mode, &type, &size);
|
||||||
|
if (!buffer)
|
||||||
|
return error("cannot read %s", sha1_to_hex(sha1));
|
||||||
|
} else {
|
||||||
|
buffer = NULL;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISLNK(mode)) {
|
||||||
if (size > sizeof(header.linkname)) {
|
if (size > sizeof(header.linkname)) {
|
||||||
sprintf(header.linkname, "see %s.paxheader",
|
sprintf(header.linkname, "see %s.paxheader",
|
||||||
sha1_to_hex(sha1));
|
sha1_to_hex(sha1));
|
||||||
@ -214,13 +228,16 @@ static int write_tar_entry(struct archiver_args *args,
|
|||||||
if (ext_header.len > 0) {
|
if (ext_header.len > 0) {
|
||||||
err = write_extended_header(args, sha1, ext_header.buf,
|
err = write_extended_header(args, sha1, ext_header.buf,
|
||||||
ext_header.len);
|
ext_header.len);
|
||||||
if (err)
|
if (err) {
|
||||||
|
free(buffer);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
strbuf_release(&ext_header);
|
strbuf_release(&ext_header);
|
||||||
write_blocked(&header, sizeof(header));
|
write_blocked(&header, sizeof(header));
|
||||||
if (S_ISREG(mode) && buffer && size > 0)
|
if (S_ISREG(mode) && buffer && size > 0)
|
||||||
write_blocked(buffer, size);
|
write_blocked(buffer, size);
|
||||||
|
free(buffer);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,8 +121,9 @@ static void *zlib_deflate(void *data, unsigned long size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int write_zip_entry(struct archiver_args *args,
|
static int write_zip_entry(struct archiver_args *args,
|
||||||
const unsigned char *sha1, const char *path, size_t pathlen,
|
const unsigned char *sha1,
|
||||||
unsigned int mode, void *buffer, unsigned long size)
|
const char *path, size_t pathlen,
|
||||||
|
unsigned int mode)
|
||||||
{
|
{
|
||||||
struct zip_local_header header;
|
struct zip_local_header header;
|
||||||
struct zip_dir_header dirent;
|
struct zip_dir_header dirent;
|
||||||
@ -134,6 +135,8 @@ static int write_zip_entry(struct archiver_args *args,
|
|||||||
int method;
|
int method;
|
||||||
unsigned char *out;
|
unsigned char *out;
|
||||||
void *deflated = NULL;
|
void *deflated = NULL;
|
||||||
|
void *buffer;
|
||||||
|
unsigned long size;
|
||||||
|
|
||||||
crc = crc32(0, NULL, 0);
|
crc = crc32(0, NULL, 0);
|
||||||
|
|
||||||
@ -148,7 +151,14 @@ static int write_zip_entry(struct archiver_args *args,
|
|||||||
out = NULL;
|
out = NULL;
|
||||||
uncompressed_size = 0;
|
uncompressed_size = 0;
|
||||||
compressed_size = 0;
|
compressed_size = 0;
|
||||||
|
buffer = NULL;
|
||||||
|
size = 0;
|
||||||
} else if (S_ISREG(mode) || S_ISLNK(mode)) {
|
} else if (S_ISREG(mode) || S_ISLNK(mode)) {
|
||||||
|
enum object_type type;
|
||||||
|
buffer = sha1_file_to_archive(args, path, sha1, mode, &type, &size);
|
||||||
|
if (!buffer)
|
||||||
|
return error("cannot read %s", sha1_to_hex(sha1));
|
||||||
|
|
||||||
method = 0;
|
method = 0;
|
||||||
attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
|
attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
|
||||||
(mode & 0111) ? ((mode) << 16) : 0;
|
(mode & 0111) ? ((mode) << 16) : 0;
|
||||||
@ -229,6 +239,7 @@ static int write_zip_entry(struct archiver_args *args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
free(deflated);
|
free(deflated);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
26
archive.c
26
archive.c
@ -59,12 +59,15 @@ static void format_subst(const struct commit *commit,
|
|||||||
free(to_free);
|
free(to_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
|
void *sha1_file_to_archive(const struct archiver_args *args,
|
||||||
|
const char *path, const unsigned char *sha1,
|
||||||
unsigned int mode, enum object_type *type,
|
unsigned int mode, enum object_type *type,
|
||||||
unsigned long *sizep, const struct commit *commit)
|
unsigned long *sizep)
|
||||||
{
|
{
|
||||||
void *buffer;
|
void *buffer;
|
||||||
|
const struct commit *commit = args->convert ? args->commit : NULL;
|
||||||
|
|
||||||
|
path += args->baselen;
|
||||||
buffer = read_sha1_file(sha1, type, sizep);
|
buffer = read_sha1_file(sha1, type, sizep);
|
||||||
if (buffer && S_ISREG(mode)) {
|
if (buffer && S_ISREG(mode)) {
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
@ -109,12 +112,9 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
|
|||||||
write_archive_entry_fn_t write_entry = c->write_entry;
|
write_archive_entry_fn_t write_entry = c->write_entry;
|
||||||
struct git_attr_check check[2];
|
struct git_attr_check check[2];
|
||||||
const char *path_without_prefix;
|
const char *path_without_prefix;
|
||||||
int convert = 0;
|
|
||||||
int err;
|
int err;
|
||||||
enum object_type type;
|
|
||||||
unsigned long size;
|
|
||||||
void *buffer;
|
|
||||||
|
|
||||||
|
args->convert = 0;
|
||||||
strbuf_reset(&path);
|
strbuf_reset(&path);
|
||||||
strbuf_grow(&path, PATH_MAX);
|
strbuf_grow(&path, PATH_MAX);
|
||||||
strbuf_add(&path, args->base, args->baselen);
|
strbuf_add(&path, args->base, args->baselen);
|
||||||
@ -126,28 +126,22 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
|
|||||||
if (!git_check_attr(path_without_prefix, ARRAY_SIZE(check), check)) {
|
if (!git_check_attr(path_without_prefix, ARRAY_SIZE(check), check)) {
|
||||||
if (ATTR_TRUE(check[0].value))
|
if (ATTR_TRUE(check[0].value))
|
||||||
return 0;
|
return 0;
|
||||||
convert = ATTR_TRUE(check[1].value);
|
args->convert = ATTR_TRUE(check[1].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
|
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
|
||||||
strbuf_addch(&path, '/');
|
strbuf_addch(&path, '/');
|
||||||
if (args->verbose)
|
if (args->verbose)
|
||||||
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
|
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
|
||||||
err = write_entry(args, sha1, path.buf, path.len, mode, NULL, 0);
|
err = write_entry(args, sha1, path.buf, path.len, mode);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
|
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = sha1_file_to_archive(path_without_prefix, sha1, mode,
|
|
||||||
&type, &size, convert ? args->commit : NULL);
|
|
||||||
if (!buffer)
|
|
||||||
return error("cannot read %s", sha1_to_hex(sha1));
|
|
||||||
if (args->verbose)
|
if (args->verbose)
|
||||||
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
|
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
|
||||||
err = write_entry(args, sha1, path.buf, path.len, mode, buffer, size);
|
return write_entry(args, sha1, path.buf, path.len, mode);
|
||||||
free(buffer);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_archive_entries(struct archiver_args *args,
|
int write_archive_entries(struct archiver_args *args,
|
||||||
@ -167,7 +161,7 @@ int write_archive_entries(struct archiver_args *args,
|
|||||||
if (args->verbose)
|
if (args->verbose)
|
||||||
fprintf(stderr, "%.*s\n", (int)len, args->base);
|
fprintf(stderr, "%.*s\n", (int)len, args->base);
|
||||||
err = write_entry(args, args->tree->object.sha1, args->base,
|
err = write_entry(args, args->tree->object.sha1, args->base,
|
||||||
len, 040777, NULL, 0);
|
len, 040777);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
10
archive.h
10
archive.h
@ -11,6 +11,7 @@ struct archiver_args {
|
|||||||
const char **pathspec;
|
const char **pathspec;
|
||||||
unsigned int verbose : 1;
|
unsigned int verbose : 1;
|
||||||
unsigned int worktree_attributes : 1;
|
unsigned int worktree_attributes : 1;
|
||||||
|
unsigned int convert : 1;
|
||||||
int compression_level;
|
int compression_level;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,11 +28,18 @@ extern void register_archiver(struct archiver *);
|
|||||||
extern void init_tar_archiver(void);
|
extern void init_tar_archiver(void);
|
||||||
extern void init_zip_archiver(void);
|
extern void init_zip_archiver(void);
|
||||||
|
|
||||||
typedef int (*write_archive_entry_fn_t)(struct archiver_args *args, const unsigned char *sha1, const char *path, size_t pathlen, unsigned int mode, void *buffer, unsigned long size);
|
typedef int (*write_archive_entry_fn_t)(struct archiver_args *args,
|
||||||
|
const unsigned char *sha1,
|
||||||
|
const char *path, size_t pathlen,
|
||||||
|
unsigned int mode);
|
||||||
|
|
||||||
extern int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
|
extern int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
|
||||||
extern int write_archive(int argc, const char **argv, const char *prefix, int setup_prefix, const char *name_hint, int remote);
|
extern int write_archive(int argc, const char **argv, const char *prefix, int setup_prefix, const char *name_hint, int remote);
|
||||||
|
|
||||||
const char *archive_format_from_filename(const char *filename);
|
const char *archive_format_from_filename(const char *filename);
|
||||||
|
extern void *sha1_file_to_archive(const struct archiver_args *args,
|
||||||
|
const char *path, const unsigned char *sha1,
|
||||||
|
unsigned int mode, enum object_type *type,
|
||||||
|
unsigned long *sizep);
|
||||||
|
|
||||||
#endif /* ARCHIVE_H */
|
#endif /* ARCHIVE_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user