archive: read short blobs in archive.c::write_archive_entry()

Centralize reading of symlink destinations and the contents of regular
files that are too small to be streamed.  This reduces code duplication
and allows future patches to add support for adding non-tracked files to
archives.  The backends are expected to stream blobs if buffer is NULL.

object_file_to_archive() is only called from archive.c and thus no
longer exported.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
René Scharfe 2020-09-19 23:23:32 +02:00 коммит произвёл Junio C Hamano
Родитель 385c171a01
Коммит 200589abcb
4 изменённых файлов: 34 добавлений и 48 удалений

Просмотреть файл

@ -242,13 +242,12 @@ static void write_extended_header(struct archiver_args *args,
static int write_tar_entry(struct archiver_args *args,
const struct object_id *oid,
const char *path, size_t pathlen,
unsigned int mode)
unsigned int mode,
void *buffer, unsigned long size)
{
struct ustar_header header;
struct strbuf ext_header = STRBUF_INIT;
unsigned int old_mode = mode;
unsigned long size, size_in_header;
void *buffer;
unsigned long size_in_header;
int err = 0;
memset(&header, 0, sizeof(header));
@ -282,20 +281,6 @@ static int write_tar_entry(struct archiver_args *args,
} else
memcpy(header.name, path, pathlen);
if (S_ISREG(mode) && !args->convert &&
oid_object_info(args->repo, oid, &size) == OBJ_BLOB &&
size > big_file_threshold)
buffer = NULL;
else if (S_ISLNK(mode) || S_ISREG(mode)) {
enum object_type type;
buffer = object_file_to_archive(args, path, oid, old_mode, &type, &size);
if (!buffer)
return error(_("cannot read %s"), oid_to_hex(oid));
} else {
buffer = NULL;
size = 0;
}
if (S_ISLNK(mode)) {
if (size > sizeof(header.linkname)) {
xsnprintf(header.linkname, sizeof(header.linkname),
@ -326,7 +311,6 @@ static int write_tar_entry(struct archiver_args *args,
else
err = stream_blocked(args->repo, oid);
}
free(buffer);
return err;
}

Просмотреть файл

@ -285,7 +285,8 @@ static int entry_is_binary(struct index_state *istate, const char *path,
static int write_zip_entry(struct archiver_args *args,
const struct object_id *oid,
const char *path, size_t pathlen,
unsigned int mode)
unsigned int mode,
void *buffer, unsigned long size)
{
struct zip_local_header header;
uintmax_t offset = zip_offset;
@ -299,10 +300,8 @@ static int write_zip_entry(struct archiver_args *args,
enum zip_method method;
unsigned char *out;
void *deflated = NULL;
void *buffer;
struct git_istream *stream = NULL;
unsigned long flags = 0;
unsigned long size;
int is_binary = -1;
const char *path_without_prefix = path + args->baselen;
unsigned int creator_version = 0;
@ -328,13 +327,8 @@ static int write_zip_entry(struct archiver_args *args,
method = ZIP_METHOD_STORE;
attr2 = 16;
out = NULL;
size = 0;
compressed_size = 0;
buffer = NULL;
} else if (S_ISREG(mode) || S_ISLNK(mode)) {
enum object_type type = oid_object_info(args->repo, oid,
&size);
method = ZIP_METHOD_STORE;
attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
(mode & 0111) ? ((mode) << 16) : 0;
@ -343,21 +337,16 @@ static int write_zip_entry(struct archiver_args *args,
if (S_ISREG(mode) && args->compression_level != 0 && size > 0)
method = ZIP_METHOD_DEFLATE;
if (S_ISREG(mode) && type == OBJ_BLOB && !args->convert &&
size > big_file_threshold) {
if (!buffer) {
enum object_type type;
stream = open_istream(args->repo, oid, &type, &size,
NULL);
if (!stream)
return error(_("cannot stream blob %s"),
oid_to_hex(oid));
flags |= ZIP_STREAM;
out = buffer = NULL;
out = NULL;
} else {
buffer = object_file_to_archive(args, path, oid, mode,
&type, &size);
if (!buffer)
return error(_("cannot read %s"),
oid_to_hex(oid));
crc = crc32(crc, buffer, size);
is_binary = entry_is_binary(args->repo->index,
path_without_prefix,
@ -511,7 +500,6 @@ static int write_zip_entry(struct archiver_args *args,
}
free(deflated);
free(buffer);
if (compressed_size > 0xffffffff || size > 0xffffffff ||
offset > 0xffffffff) {

Просмотреть файл

@ -70,10 +70,12 @@ static void format_subst(const struct commit *commit,
free(to_free);
}
void *object_file_to_archive(const struct archiver_args *args,
const char *path, const struct object_id *oid,
unsigned int mode, enum object_type *type,
unsigned long *sizep)
static void *object_file_to_archive(const struct archiver_args *args,
const char *path,
const struct object_id *oid,
unsigned int mode,
enum object_type *type,
unsigned long *sizep)
{
void *buffer;
const struct commit *commit = args->convert ? args->commit : NULL;
@ -145,6 +147,9 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
write_archive_entry_fn_t write_entry = c->write_entry;
int err;
const char *path_without_prefix;
unsigned long size;
void *buffer;
enum object_type type;
args->convert = 0;
strbuf_reset(&path);
@ -167,7 +172,7 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
err = write_entry(args, oid, path.buf, path.len, mode);
err = write_entry(args, oid, path.buf, path.len, mode, NULL, 0);
if (err)
return err;
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
@ -175,7 +180,19 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
return write_entry(args, oid, path.buf, path.len, mode);
/* Stream it? */
if (S_ISREG(mode) && !args->convert &&
oid_object_info(args->repo, oid, &size) == OBJ_BLOB &&
size > big_file_threshold)
return write_entry(args, oid, path.buf, path.len, mode, NULL, size);
buffer = object_file_to_archive(args, path.buf, oid, mode, &type, &size);
if (!buffer)
return error(_("cannot read %s"), oid_to_hex(oid));
err = write_entry(args, oid, path.buf, path.len, mode, buffer, size);
free(buffer);
return err;
}
static void queue_directory(const unsigned char *sha1,
@ -265,7 +282,7 @@ int write_archive_entries(struct archiver_args *args,
if (args->verbose)
fprintf(stderr, "%.*s\n", (int)len, args->base);
err = write_entry(args, &args->tree->object.oid, args->base,
len, 040777);
len, 040777, NULL, 0);
if (err)
return err;
}

Просмотреть файл

@ -49,12 +49,9 @@ void init_archivers(void);
typedef int (*write_archive_entry_fn_t)(struct archiver_args *args,
const struct object_id *oid,
const char *path, size_t pathlen,
unsigned int mode);
unsigned int mode,
void *buffer, unsigned long size);
int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
void *object_file_to_archive(const struct archiver_args *args,
const char *path, const struct object_id *oid,
unsigned int mode, enum object_type *type,
unsigned long *sizep);
#endif /* ARCHIVE_H */