Git fork
at reftables-rust 546 lines 14 kB view raw
1/* 2 * Copyright (c) 2005, 2006 Rene Scharfe 3 */ 4 5#define USE_THE_REPOSITORY_VARIABLE 6 7#include "git-compat-util.h" 8#include "config.h" 9#include "gettext.h" 10#include "git-zlib.h" 11#include "hex.h" 12#include "tar.h" 13#include "archive.h" 14#include "odb.h" 15#include "strbuf.h" 16#include "streaming.h" 17#include "run-command.h" 18#include "write-or-die.h" 19 20#define RECORDSIZE (512) 21#define BLOCKSIZE (RECORDSIZE * 20) 22 23static char block[BLOCKSIZE]; 24static unsigned long offset; 25 26static int tar_umask = 002; 27 28static int write_tar_filter_archive(const struct archiver *ar, 29 struct archiver_args *args); 30 31/* 32 * This is the max value that a ustar size header can specify, as it is fixed 33 * at 11 octal digits. POSIX specifies that we switch to extended headers at 34 * this size. 35 * 36 * Likewise for the mtime (which happens to use a buffer of the same size). 37 */ 38#if ULONG_MAX == 0xFFFFFFFF 39#define USTAR_MAX_SIZE ULONG_MAX 40#else 41#define USTAR_MAX_SIZE 077777777777UL 42#endif 43#if TIME_MAX == 0xFFFFFFFF 44#define USTAR_MAX_MTIME TIME_MAX 45#else 46#define USTAR_MAX_MTIME 077777777777ULL 47#endif 48 49static void tar_write_block(const void *buf) 50{ 51 write_or_die(1, buf, BLOCKSIZE); 52} 53 54static void (*write_block)(const void *) = tar_write_block; 55 56/* writes out the whole block, but only if it is full */ 57static void write_if_needed(void) 58{ 59 if (offset == BLOCKSIZE) { 60 write_block(block); 61 offset = 0; 62 } 63} 64 65/* 66 * queues up writes, so that all our write(2) calls write exactly one 67 * full block; pads writes to RECORDSIZE 68 */ 69static void do_write_blocked(const void *data, unsigned long size) 70{ 71 const char *buf = data; 72 73 if (offset) { 74 unsigned long chunk = BLOCKSIZE - offset; 75 if (size < chunk) 76 chunk = size; 77 memcpy(block + offset, buf, chunk); 78 size -= chunk; 79 offset += chunk; 80 buf += chunk; 81 write_if_needed(); 82 } 83 while (size >= BLOCKSIZE) { 84 write_block(buf); 85 size -= BLOCKSIZE; 86 buf += BLOCKSIZE; 87 } 88 if (size) { 89 memcpy(block + offset, buf, size); 90 offset += size; 91 } 92} 93 94static void finish_record(void) 95{ 96 unsigned long tail; 97 tail = offset % RECORDSIZE; 98 if (tail) { 99 memset(block + offset, 0, RECORDSIZE - tail); 100 offset += RECORDSIZE - tail; 101 } 102 write_if_needed(); 103} 104 105static void write_blocked(const void *data, unsigned long size) 106{ 107 do_write_blocked(data, size); 108 finish_record(); 109} 110 111/* 112 * The end of tar archives is marked by 2*512 nul bytes and after that 113 * follows the rest of the block (if any). 114 */ 115static void write_trailer(void) 116{ 117 int tail = BLOCKSIZE - offset; 118 memset(block + offset, 0, tail); 119 write_block(block); 120 if (tail < 2 * RECORDSIZE) { 121 memset(block, 0, offset); 122 write_block(block); 123 } 124} 125 126/* 127 * queues up writes, so that all our write(2) calls write exactly one 128 * full block; pads writes to RECORDSIZE 129 */ 130static int stream_blocked(struct repository *r, const struct object_id *oid) 131{ 132 struct git_istream *st; 133 enum object_type type; 134 unsigned long sz; 135 char buf[BLOCKSIZE]; 136 ssize_t readlen; 137 138 st = open_istream(r, oid, &type, &sz, NULL); 139 if (!st) 140 return error(_("cannot stream blob %s"), oid_to_hex(oid)); 141 for (;;) { 142 readlen = read_istream(st, buf, sizeof(buf)); 143 if (readlen <= 0) 144 break; 145 do_write_blocked(buf, readlen); 146 } 147 close_istream(st); 148 if (!readlen) 149 finish_record(); 150 return readlen; 151} 152 153/* 154 * pax extended header records have the format "%u %s=%s\n". %u contains 155 * the size of the whole string (including the %u), the first %s is the 156 * keyword, the second one is the value. This function constructs such a 157 * string and appends it to a struct strbuf. 158 */ 159static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword, 160 const char *value, size_t valuelen) 161{ 162 size_t orig_len = sb->len; 163 size_t len, tmp; 164 165 /* "%u %s=%s\n" */ 166 len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1; 167 for (tmp = 1; len / 10 >= tmp; tmp *= 10) 168 len++; 169 170 strbuf_grow(sb, len); 171 strbuf_addf(sb, "%"PRIuMAX" %s=", (uintmax_t)len, keyword); 172 strbuf_add(sb, value, valuelen); 173 strbuf_addch(sb, '\n'); 174 175 if (len != sb->len - orig_len) 176 BUG("pax extended header length miscalculated as %"PRIuMAX 177 ", should be %"PRIuMAX, 178 (uintmax_t)len, (uintmax_t)(sb->len - orig_len)); 179} 180 181/* 182 * Like strbuf_append_ext_header, but for numeric values. 183 */ 184static void strbuf_append_ext_header_uint(struct strbuf *sb, 185 const char *keyword, 186 uintmax_t value) 187{ 188 char buf[40]; /* big enough for 2^128 in decimal, plus NUL */ 189 int len; 190 191 len = xsnprintf(buf, sizeof(buf), "%"PRIuMAX, value); 192 strbuf_append_ext_header(sb, keyword, buf, len); 193} 194 195static unsigned int ustar_header_chksum(const struct ustar_header *header) 196{ 197 const unsigned char *p = (const unsigned char *)header; 198 unsigned int chksum = 0; 199 while (p < (const unsigned char *)header->chksum) 200 chksum += *p++; 201 chksum += sizeof(header->chksum) * ' '; 202 p += sizeof(header->chksum); 203 while (p < (const unsigned char *)header + sizeof(struct ustar_header)) 204 chksum += *p++; 205 return chksum; 206} 207 208static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen) 209{ 210 size_t i = pathlen; 211 if (i > 1 && path[i - 1] == '/') 212 i--; 213 if (i > maxlen) 214 i = maxlen; 215 do { 216 i--; 217 } while (i > 0 && path[i] != '/'); 218 return i; 219} 220 221static void prepare_header(struct archiver_args *args, 222 struct ustar_header *header, 223 unsigned int mode, unsigned long size) 224{ 225 xsnprintf(header->mode, sizeof(header->mode), "%07o", mode & 07777); 226 xsnprintf(header->size, sizeof(header->size), "%011"PRIoMAX , S_ISREG(mode) ? (uintmax_t)size : (uintmax_t)0); 227 xsnprintf(header->mtime, sizeof(header->mtime), "%011lo", (unsigned long) args->time); 228 229 xsnprintf(header->uid, sizeof(header->uid), "%07o", 0); 230 xsnprintf(header->gid, sizeof(header->gid), "%07o", 0); 231 strlcpy(header->uname, "root", sizeof(header->uname)); 232 strlcpy(header->gname, "root", sizeof(header->gname)); 233 xsnprintf(header->devmajor, sizeof(header->devmajor), "%07o", 0); 234 xsnprintf(header->devminor, sizeof(header->devminor), "%07o", 0); 235 236 memcpy(header->magic, "ustar", 6); 237 memcpy(header->version, "00", 2); 238 239 xsnprintf(header->chksum, sizeof(header->chksum), "%07o", ustar_header_chksum(header)); 240} 241 242static void write_extended_header(struct archiver_args *args, 243 const struct object_id *oid, 244 const void *buffer, unsigned long size) 245{ 246 struct ustar_header header; 247 unsigned int mode; 248 memset(&header, 0, sizeof(header)); 249 *header.typeflag = TYPEFLAG_EXT_HEADER; 250 mode = 0100666; 251 xsnprintf(header.name, sizeof(header.name), "%s.paxheader", oid_to_hex(oid)); 252 prepare_header(args, &header, mode, size); 253 write_blocked(&header, sizeof(header)); 254 write_blocked(buffer, size); 255} 256 257static int write_tar_entry(struct archiver_args *args, 258 const struct object_id *oid, 259 const char *path, size_t pathlen, 260 unsigned int mode, 261 void *buffer, unsigned long size) 262{ 263 struct ustar_header header; 264 struct strbuf ext_header = STRBUF_INIT; 265 unsigned long size_in_header; 266 int err = 0; 267 268 memset(&header, 0, sizeof(header)); 269 270 if (S_ISDIR(mode) || S_ISGITLINK(mode)) { 271 *header.typeflag = TYPEFLAG_DIR; 272 mode = (mode | 0777) & ~tar_umask; 273 } else if (S_ISLNK(mode)) { 274 *header.typeflag = TYPEFLAG_LNK; 275 mode |= 0777; 276 } else if (S_ISREG(mode)) { 277 *header.typeflag = TYPEFLAG_REG; 278 mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask; 279 } else { 280 return error(_("unsupported file mode: 0%o (SHA1: %s)"), 281 mode, oid_to_hex(oid)); 282 } 283 if (pathlen > sizeof(header.name)) { 284 size_t plen = get_path_prefix(path, pathlen, 285 sizeof(header.prefix)); 286 size_t rest = pathlen - plen - 1; 287 if (plen > 0 && rest <= sizeof(header.name)) { 288 memcpy(header.prefix, path, plen); 289 memcpy(header.name, path + plen + 1, rest); 290 } else { 291 xsnprintf(header.name, sizeof(header.name), "%s.data", 292 oid_to_hex(oid)); 293 strbuf_append_ext_header(&ext_header, "path", 294 path, pathlen); 295 } 296 } else 297 memcpy(header.name, path, pathlen); 298 299 if (S_ISLNK(mode)) { 300 if (size > sizeof(header.linkname)) { 301 xsnprintf(header.linkname, sizeof(header.linkname), 302 "see %s.paxheader", oid_to_hex(oid)); 303 strbuf_append_ext_header(&ext_header, "linkpath", 304 buffer, size); 305 } else 306 memcpy(header.linkname, buffer, size); 307 } 308 309 size_in_header = size; 310 if (S_ISREG(mode) && size > USTAR_MAX_SIZE) { 311 size_in_header = 0; 312 strbuf_append_ext_header_uint(&ext_header, "size", size); 313 } 314 315 prepare_header(args, &header, mode, size_in_header); 316 317 if (ext_header.len > 0) { 318 write_extended_header(args, oid, ext_header.buf, 319 ext_header.len); 320 } 321 strbuf_release(&ext_header); 322 write_blocked(&header, sizeof(header)); 323 if (S_ISREG(mode) && size > 0) { 324 if (buffer) 325 write_blocked(buffer, size); 326 else 327 err = stream_blocked(args->repo, oid); 328 } 329 return err; 330} 331 332static void write_global_extended_header(struct archiver_args *args) 333{ 334 const struct object_id *oid = args->commit_oid; 335 struct strbuf ext_header = STRBUF_INIT; 336 struct ustar_header header; 337 unsigned int mode; 338 339 if (oid) 340 strbuf_append_ext_header(&ext_header, "comment", 341 oid_to_hex(oid), 342 the_hash_algo->hexsz); 343 if (args->time > USTAR_MAX_MTIME) { 344 strbuf_append_ext_header_uint(&ext_header, "mtime", 345 args->time); 346 args->time = USTAR_MAX_MTIME; 347 } 348 349 if (!ext_header.len) 350 return; 351 352 memset(&header, 0, sizeof(header)); 353 *header.typeflag = TYPEFLAG_GLOBAL_HEADER; 354 mode = 0100666; 355 xsnprintf(header.name, sizeof(header.name), "pax_global_header"); 356 prepare_header(args, &header, mode, ext_header.len); 357 write_blocked(&header, sizeof(header)); 358 write_blocked(ext_header.buf, ext_header.len); 359 strbuf_release(&ext_header); 360} 361 362static struct archiver **tar_filters; 363static int nr_tar_filters; 364static int alloc_tar_filters; 365 366static struct archiver *find_tar_filter(const char *name, size_t len) 367{ 368 int i; 369 for (i = 0; i < nr_tar_filters; i++) { 370 struct archiver *ar = tar_filters[i]; 371 if (!xstrncmpz(ar->name, name, len)) 372 return ar; 373 } 374 return NULL; 375} 376 377static int tar_filter_config(const char *var, const char *value, 378 void *data UNUSED) 379{ 380 struct archiver *ar; 381 const char *name; 382 const char *type; 383 size_t namelen; 384 385 if (parse_config_key(var, "tar", &name, &namelen, &type) < 0 || !name) 386 return 0; 387 388 ar = find_tar_filter(name, namelen); 389 if (!ar) { 390 CALLOC_ARRAY(ar, 1); 391 ar->name = xmemdupz(name, namelen); 392 ar->write_archive = write_tar_filter_archive; 393 ar->flags = ARCHIVER_WANT_COMPRESSION_LEVELS | 394 ARCHIVER_HIGH_COMPRESSION_LEVELS; 395 ALLOC_GROW(tar_filters, nr_tar_filters + 1, alloc_tar_filters); 396 tar_filters[nr_tar_filters++] = ar; 397 } 398 399 if (!strcmp(type, "command")) { 400 if (!value) 401 return config_error_nonbool(var); 402 free(ar->filter_command); 403 ar->filter_command = xstrdup(value); 404 return 0; 405 } 406 if (!strcmp(type, "remote")) { 407 if (git_config_bool(var, value)) 408 ar->flags |= ARCHIVER_REMOTE; 409 else 410 ar->flags &= ~ARCHIVER_REMOTE; 411 return 0; 412 } 413 414 return 0; 415} 416 417static int git_tar_config(const char *var, const char *value, 418 const struct config_context *ctx, void *cb) 419{ 420 if (!strcmp(var, "tar.umask")) { 421 if (value && !strcmp(value, "user")) { 422 tar_umask = umask(0); 423 umask(tar_umask); 424 } else { 425 tar_umask = git_config_int(var, value, ctx->kvi); 426 } 427 return 0; 428 } 429 430 return tar_filter_config(var, value, cb); 431} 432 433static int write_tar_archive(const struct archiver *ar UNUSED, 434 struct archiver_args *args) 435{ 436 int err = 0; 437 438 write_global_extended_header(args); 439 err = write_archive_entries(args, write_tar_entry); 440 if (!err) 441 write_trailer(); 442 return err; 443} 444 445static git_zstream gzstream; 446static unsigned char outbuf[16384]; 447 448static void tgz_deflate(int flush) 449{ 450 while (gzstream.avail_in || flush == Z_FINISH) { 451 int status = git_deflate(&gzstream, flush); 452 if (!gzstream.avail_out || status == Z_STREAM_END) { 453 write_or_die(1, outbuf, gzstream.next_out - outbuf); 454 gzstream.next_out = outbuf; 455 gzstream.avail_out = sizeof(outbuf); 456 if (status == Z_STREAM_END) 457 break; 458 } 459 if (status != Z_OK && status != Z_BUF_ERROR) 460 die(_("deflate error (%d)"), status); 461 } 462} 463 464static void tgz_write_block(const void *data) 465{ 466 gzstream.next_in = (void *)data; 467 gzstream.avail_in = BLOCKSIZE; 468 tgz_deflate(Z_NO_FLUSH); 469} 470 471static const char internal_gzip_command[] = "git archive gzip"; 472 473static int write_tar_filter_archive(const struct archiver *ar, 474 struct archiver_args *args) 475{ 476 struct gz_header_s gzhead = { .os = 3 }; /* Unix, for reproducibility */ 477 struct strbuf cmd = STRBUF_INIT; 478 struct child_process filter = CHILD_PROCESS_INIT; 479 int r; 480 481 if (!ar->filter_command) 482 BUG("tar-filter archiver called with no filter defined"); 483 484 if (!strcmp(ar->filter_command, internal_gzip_command)) { 485 write_block = tgz_write_block; 486 git_deflate_init_gzip(&gzstream, args->compression_level); 487 if (deflateSetHeader(&gzstream.z, &gzhead) != Z_OK) 488 BUG("deflateSetHeader() called too late"); 489 gzstream.next_out = outbuf; 490 gzstream.avail_out = sizeof(outbuf); 491 492 r = write_tar_archive(ar, args); 493 494 tgz_deflate(Z_FINISH); 495 git_deflate_end(&gzstream); 496 return r; 497 } 498 499 strbuf_addstr(&cmd, ar->filter_command); 500 if (args->compression_level >= 0) 501 strbuf_addf(&cmd, " -%d", args->compression_level); 502 503 strvec_push(&filter.args, cmd.buf); 504 filter.use_shell = 1; 505 filter.in = -1; 506 filter.silent_exec_failure = 1; 507 508 if (start_command(&filter) < 0) 509 die_errno(_("unable to start '%s' filter"), cmd.buf); 510 close(1); 511 if (dup2(filter.in, 1) < 0) 512 die_errno(_("unable to redirect descriptor")); 513 close(filter.in); 514 515 r = write_tar_archive(ar, args); 516 517 close(1); 518 if (finish_command(&filter) != 0) 519 die(_("'%s' filter reported error"), cmd.buf); 520 521 strbuf_release(&cmd); 522 return r; 523} 524 525static struct archiver tar_archiver = { 526 .name = "tar", 527 .write_archive = write_tar_archive, 528 .flags = ARCHIVER_REMOTE, 529}; 530 531void init_tar_archiver(void) 532{ 533 int i; 534 register_archiver(&tar_archiver); 535 536 tar_filter_config("tar.tgz.command", internal_gzip_command, NULL); 537 tar_filter_config("tar.tgz.remote", "true", NULL); 538 tar_filter_config("tar.tar.gz.command", internal_gzip_command, NULL); 539 tar_filter_config("tar.tar.gz.remote", "true", NULL); 540 repo_config(the_repository, git_tar_config, NULL); 541 for (i = 0; i < nr_tar_filters; i++) { 542 /* omit any filters that never had a command configured */ 543 if (tar_filters[i]->filter_command) 544 register_archiver(tar_filters[i]); 545 } 546}