struct git_istream *open_istream(const unsigned char *sha1, enum object_type *type, unsigned long *size, struct stream_filter *filter) { struct git_istream *st; struct object_info oi = {0}; const unsigned char *real = lookup_replace_object(sha1); enum input_source src = istream_source(real, type, &oi); if (src < 0) return NULL; st = xmalloc(sizeof(*st)); if (open_istream_tbl[src](st, &oi, real, type)) { if (open_istream_incore(st, &oi, real, type)) { free(st); return NULL; } } if (filter) { /* Add "&& !is_null_stream_filter(filter)" for performance */ struct git_istream *nst = attach_stream_filter(st, filter); if (!nst) close_istream(st); st = nst; } *size = st->size; return st; }
int stream_blob_to_fd(int fd, unsigned const char *sha1, struct stream_filter *filter, int can_seek) { struct git_istream *st; enum object_type type; unsigned long sz; ssize_t kept = 0; int result = -1; st = open_istream(sha1, &type, &sz, filter); if (!st) { if (filter) free_stream_filter(filter); return result; } if (type != OBJ_BLOB) goto close_and_exit; for (;;) { char buf[1024 * 16]; ssize_t wrote, holeto; ssize_t readlen = read_istream(st, buf, sizeof(buf)); if (readlen < 0) goto close_and_exit; if (!readlen) break; if (can_seek && sizeof(buf) == readlen) { for (holeto = 0; holeto < readlen; holeto++) if (buf[holeto]) break; if (readlen == holeto) { kept += holeto; continue; } } if (kept && lseek(fd, kept, SEEK_CUR) == (off_t) -1) goto close_and_exit; else kept = 0; wrote = write_in_full(fd, buf, readlen); if (wrote != readlen) goto close_and_exit; } if (kept && (lseek(fd, kept - 1, SEEK_CUR) == (off_t) -1 || xwrite(fd, "", 1) != 1)) goto close_and_exit; result = 0; close_and_exit: close_istream(st); return result; }
/* * queues up writes, so that all our write(2) calls write exactly one * full block; pads writes to RECORDSIZE */ static int stream_blocked(const unsigned char *sha1) { struct git_istream *st; enum object_type type; unsigned long sz; char buf[BLOCKSIZE]; ssize_t readlen; st = open_istream(sha1, &type, &sz, NULL); if (!st) return error("cannot stream blob %s", sha1_to_hex(sha1)); for (;;) { readlen = read_istream(st, buf, sizeof(buf)); if (readlen <= 0) break; do_write_blocked(buf, readlen); } close_istream(st); if (!readlen) finish_record(); return readlen; }
static close_method_decl(filtered) { free_stream_filter(st->u.filtered.filter); return close_istream(st->u.filtered.upstream); }
static int write_zip_entry(struct archiver_args *args, const unsigned char *sha1, const char *path, size_t pathlen, unsigned int mode, int big_file_threshold, int zip_dir_size, int zip_dir_offset, int zip_dir, int zip_time, int zip_date, int zip_offset, int zip_dir_entries) { struct zip_local_header header; struct zip_dir_header dirent; struct zip_extra_mtime extra; unsigned long attr2 = 0; unsigned long compressed_size = 0; unsigned long crc = 0; unsigned long direntsize = 0; int method = 0; int out = 0; int deflated = 0; int buffer = 0; int stream = 0; unsigned long flags = 0; unsigned long size = 0; crc = crc32(0, NULL, 0); if (!has_only_ascii(path)) { if (is_utf8(path)) flags |= ZIP_UTF8; else warning("Path is not valid UTF-8: %s", path); } if (pathlen > 0xffff) { return error("path too long (%d chars, SHA1: %s): %s", (int)pathlen, sha1_to_hex(sha1), path); } if (S_ISDIR(mode) || S_ISGITLINK(mode)) { method = 0; attr2 = 16; out = NULL; size = 0; compressed_size = 0; buffer = NULL; } else if (S_ISREG(mode) || S_ISLNK(mode)) { int type = sha1_object_info(sha1, &size); method = 0; attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) : (mode & 0111) ? ((mode) << 16) : 0; if (S_ISREG(mode) && args->compression_level != 0 && size > 0) method = 8; if (method == 0) { compressed_size = size; } else { compressed_size = 0; } if (S_ISREG(mode) && type == OBJ_BLOB && !args->convert && size > big_file_threshold) { stream = open_istream(sha1, &type, &size, NULL); if (!stream) return error("cannot stream blob %s", sha1_to_hex(sha1)); flags |= ZIP_STREAM; out = buffer = NULL; } else { buffer = sha1_file_to_archive(args, path, sha1, mode, &type, &size); if (!buffer) return error("cannot read %s", sha1_to_hex(sha1)); crc = crc32(crc, buffer, size); out = buffer; } } else { return error("unsupported file mode: 0%o (SHA1: %s)", mode, sha1_to_hex(sha1)); } if (buffer && method == 8) { deflated = zlib_deflate(buffer, size, args->compression_level, &compressed_size); if (deflated && compressed_size - 6 < size) { /* ZLIB --> raw compressed data (see RFC 1950) */ /* CMF and FLG ... */ out = deflated + 2; compressed_size -= 6; /* ... and ADLER32 */ } else { method = 0; compressed_size = size; } } copy_le16(extra.magic, 0x5455); copy_le16(extra.extra_size, ZIP_EXTRA_MTIME_PAYLOAD_SIZE); extra.flags[0] = 1; /* just mtime */ copy_le32(extra.mtime, args->time); /* make sure we have enough free space in the dictionary */ direntsize = ZIP_DIR_HEADER_SIZE + pathlen + ZIP_EXTRA_MTIME_SIZE; while (zip_dir_size < zip_dir_offset + direntsize) { zip_dir_size += ZIP_DIRECTORY_MIN_SIZE; zip_dir = xrealloc(zip_dir, zip_dir_size); } copy_le32(dirent.magic, 0x02014b50); copy_le16(dirent.creator_version, S_ISLNK(mode) || (S_ISREG(mode) && (mode & 0111)) ? 0x0317 : 0); copy_le16(dirent.version, 10); copy_le16(dirent.flags, flags); copy_le16(dirent.compression_method, method); copy_le16(dirent.mtime, zip_time); copy_le16(dirent.mdate, zip_date); set_zip_dir_data_desc(&dirent, size, compressed_size, crc); copy_le16(dirent.filename_length, pathlen); copy_le16(dirent.extra_length, ZIP_EXTRA_MTIME_SIZE); copy_le16(dirent.comment_length, 0); copy_le16(dirent.disk, 0); copy_le16(dirent.attr1, 0); copy_le32(dirent.attr2, attr2); copy_le32(dirent.offset, zip_offset); copy_le32(header.magic, 0x04034b50); copy_le16(header.version, 10); copy_le16(header.flags, flags); copy_le16(header.compression_method, method); copy_le16(header.mtime, zip_time); copy_le16(header.mdate, zip_date); set_zip_header_data_desc(&header, size, compressed_size, crc); copy_le16(header.filename_length, pathlen); copy_le16(header.extra_length, ZIP_EXTRA_MTIME_SIZE); write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE); zip_offset += ZIP_LOCAL_HEADER_SIZE; write_or_die(1, path, pathlen); zip_offset += pathlen; write_or_die(1, &extra, ZIP_EXTRA_MTIME_SIZE); zip_offset += ZIP_EXTRA_MTIME_SIZE; if (stream && method == 0) { unsigned char buf[STREAM_BUFFER_SIZE]; ssize_t readlen = 0; for (;;) { readlen = read_istream(stream, buf, sizeof(buf)); if (readlen <= 0) break; crc = crc32(crc, buf, readlen); write_or_die(1, buf, readlen); } close_istream(stream); if (readlen) return readlen; compressed_size = size; zip_offset += compressed_size; write_zip_data_desc(size, compressed_size, crc); zip_offset += ZIP_DATA_DESC_SIZE; set_zip_dir_data_desc(&dirent, size, compressed_size, crc); } else if (stream && method == 8) { int buf; ssize_t readlen; git_zstream zstream; int result; size_t out_len; int compressed; memset(&zstream, 0, sizeof(zstream)); git_deflate_init(&zstream, args->compression_level); compressed_size = 0; zstream.next_out = compressed; zstream.avail_out = sizeof(compressed); for (;;) { readlen = read_istream(stream, buf, sizeof(buf)); if (readlen <= 0) break; crc = crc32(crc, buf, readlen); zstream.next_in = buf; zstream.avail_in = readlen; result = git_deflate(&zstream, 0); if (result != Z_OK) die("deflate error (%d)", result); out = compressed; if (!compressed_size) out += 2; out_len = zstream.next_out - out; if (out_len > 0) { write_or_die(1, out, out_len); compressed_size += out_len; zstream.next_out = compressed; zstream.avail_out = sizeof(compressed); } } close_istream(stream); if (readlen) return readlen; zstream.next_in = buf; zstream.avail_in = 0; result = git_deflate(&zstream, Z_FINISH); if (result != Z_STREAM_END) die("deflate error (%d)", result); git_deflate_end(&zstream); out = compressed; if (!compressed_size) out += 2; out_len = zstream.next_out - out - 4; write_or_die(1, out, out_len); compressed_size += out_len; zip_offset += compressed_size; write_zip_data_desc(size, compressed_size, crc); zip_offset += ZIP_DATA_DESC_SIZE; set_zip_dir_data_desc(&dirent, size, compressed_size, crc); } else if (compressed_size > 0) { write_or_die(1, out, compressed_size); zip_offset += compressed_size; } free(deflated); free(buffer); memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE); zip_dir_offset += ZIP_DIR_HEADER_SIZE; memcpy(zip_dir + zip_dir_offset, path, pathlen); zip_dir_offset += pathlen; memcpy(zip_dir + zip_dir_offset, &extra, ZIP_EXTRA_MTIME_SIZE); zip_dir_offset += ZIP_EXTRA_MTIME_SIZE; zip_dir_entries++; return 0; }