Skip to content

Commit

Permalink
archive: read short blobs in archive.c::write_archive_entry()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
rscharfe authored and gitster committed Sep 19, 2020
1 parent 385c171 commit 200589a
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 48 deletions.
22 changes: 3 additions & 19 deletions archive-tar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -326,7 +311,6 @@ static int write_tar_entry(struct archiver_args *args,
else
err = stream_blocked(args->repo, oid);
}
free(buffer);
return err;
}

Expand Down
22 changes: 5 additions & 17 deletions archive-zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down
31 changes: 24 additions & 7 deletions archive.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -167,15 +172,27 @@ 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);
}

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,
Expand Down Expand Up @@ -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;
}
Expand Down
7 changes: 2 additions & 5 deletions archive.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit 200589a

Please sign in to comment.