Coverage Report

Created: 2024-09-08 06:23

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