static int write_archive_entry(const unsigned char *sha1, const char *base, int baselen, const char *filename, unsigned mode, int stage, void *context) { static struct strbuf path = STRBUF_INIT; struct archiver_context *c = context; struct archiver_args *args = c->args; write_archive_entry_fn_t write_entry = c->write_entry; struct git_attr_check check[2]; const char *path_without_prefix; int convert = 0; int err; enum object_type type; unsigned long size; void *buffer; strbuf_reset(&path); strbuf_grow(&path, PATH_MAX); strbuf_add(&path, args->base, args->baselen); strbuf_add(&path, base, baselen); strbuf_addstr(&path, filename); path_without_prefix = path.buf + args->baselen; setup_archive_check(check); if (!git_checkattr(path_without_prefix, ARRAY_SIZE(check), check)) { if (ATTR_TRUE(check[0].value)) return 0; convert = ATTR_TRUE(check[1].value); } if (S_ISDIR(mode) || S_ISGITLINK(mode)) { strbuf_addch(&path, '/'); if (args->verbose) fprintf(stderr, "%.*s\n", (int)path.len, path.buf); err = write_entry(args, sha1, path.buf, path.len, mode, NULL, 0); if (err) return err; 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) fprintf(stderr, "%.*s\n", (int)path.len, path.buf); err = write_entry(args, sha1, path.buf, path.len, mode, buffer, size); free(buffer); return err; }
static int write_tar_entry(struct archiver_args *args, const unsigned char *sha1, const char *path, size_t pathlen, unsigned int mode) { struct ustar_header header; struct strbuf ext_header = STRBUF_INIT; unsigned int old_mode = mode; unsigned long size; void *buffer; int err = 0; memset(&header, 0, sizeof(header)); if (S_ISDIR(mode) || S_ISGITLINK(mode)) { *header.typeflag = TYPEFLAG_DIR; mode = (mode | 0777) & ~tar_umask; } else if (S_ISLNK(mode)) { *header.typeflag = TYPEFLAG_LNK; mode |= 0777; } else if (S_ISREG(mode)) { *header.typeflag = TYPEFLAG_REG; mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask; } else { return error("unsupported file mode: 0%o (SHA1: %s)", mode, sha1_to_hex(sha1)); } if (pathlen > sizeof(header.name)) { size_t plen = get_path_prefix(path, pathlen, sizeof(header.prefix)); size_t rest = pathlen - plen - 1; if (plen > 0 && rest <= sizeof(header.name)) { memcpy(header.prefix, path, plen); memcpy(header.name, path + plen + 1, rest); } else { sprintf(header.name, "%s.data", sha1_to_hex(sha1)); strbuf_append_ext_header(&ext_header, "path", path, pathlen); } } else memcpy(header.name, path, pathlen); if (S_ISREG(mode) && !args->convert && sha1_object_info(sha1, &size) == OBJ_BLOB && size > big_file_threshold) buffer = NULL; else 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)) { sprintf(header.linkname, "see %s.paxheader", sha1_to_hex(sha1)); strbuf_append_ext_header(&ext_header, "linkpath", buffer, size); } else memcpy(header.linkname, buffer, size); } prepare_header(args, &header, mode, size); if (ext_header.len > 0) { err = write_extended_header(args, sha1, ext_header.buf, ext_header.len); if (err) { free(buffer); return err; } } strbuf_release(&ext_header); write_blocked(&header, sizeof(header)); if (S_ISREG(mode) && size > 0) { if (buffer) write_blocked(buffer, size); else err = stream_blocked(sha1); } free(buffer); return err; }
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 = LOR(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; size = 0; } else if (S_ISREG(mode) || S_ISLNK(mode)) { int type = sha1_object_info(sha1, &size); method = 0; if (S_ISLNK(mode)) { attr2 = ASL(LOR(mode,0777),16); } else if (LAND(mode,0111)) { attr2 = ASL(LOR(mode,0111),16); } if (S_ISREG(mode) && args->compression_level != 0 && size > 0) method = 8; compressed_size = size; 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; }