Coverage Report

Created: 2024-09-08 06:23

/src/git/builtin/upload-archive.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2006 Franck Bui-Huu
3
 */
4
#include "builtin.h"
5
#include "archive.h"
6
#include "path.h"
7
#include "pkt-line.h"
8
#include "sideband.h"
9
#include "repository.h"
10
#include "run-command.h"
11
#include "strvec.h"
12
13
static const char upload_archive_usage[] =
14
  "git upload-archive <repository>";
15
16
static const char deadchild[] =
17
"git upload-archive: archiver died with error";
18
19
0
#define MAX_ARGS (64)
20
21
int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
22
0
{
23
0
  struct strvec sent_argv = STRVEC_INIT;
24
0
  const char *arg_cmd = "argument ";
25
0
  int ret;
26
27
0
  if (argc != 2 || !strcmp(argv[1], "-h"))
28
0
    usage(upload_archive_usage);
29
30
0
  if (!enter_repo(argv[1], 0))
31
0
    die("'%s' does not appear to be a git repository", argv[1]);
32
33
0
  init_archivers();
34
35
  /* put received options in sent_argv[] */
36
0
  strvec_push(&sent_argv, "git-upload-archive");
37
0
  for (;;) {
38
0
    char *buf = packet_read_line(0, NULL);
39
0
    if (!buf)
40
0
      break; /* got a flush */
41
0
    if (sent_argv.nr > MAX_ARGS)
42
0
      die("Too many options (>%d)", MAX_ARGS - 1);
43
44
0
    if (!starts_with(buf, arg_cmd))
45
0
      die("'argument' token or flush expected");
46
0
    strvec_push(&sent_argv, buf + strlen(arg_cmd));
47
0
  }
48
49
  /* parse all options sent by the client */
50
0
  ret = write_archive(sent_argv.nr, sent_argv.v, prefix,
51
0
          the_repository, NULL, 1);
52
53
0
  strvec_clear(&sent_argv);
54
0
  return ret;
55
0
}
56
57
__attribute__((format (printf, 1, 2)))
58
static void error_clnt(const char *fmt, ...)
59
0
{
60
0
  struct strbuf buf = STRBUF_INIT;
61
0
  va_list params;
62
63
0
  va_start(params, fmt);
64
0
  strbuf_vaddf(&buf, fmt, params);
65
0
  va_end(params);
66
0
  send_sideband(1, 3, buf.buf, buf.len, LARGE_PACKET_MAX);
67
0
  die("sent error to the client: %s", buf.buf);
68
0
}
69
70
static ssize_t process_input(int child_fd, int band)
71
0
{
72
0
  char buf[16384];
73
0
  ssize_t sz = read(child_fd, buf, sizeof(buf));
74
0
  if (sz < 0) {
75
0
    if (errno != EAGAIN && errno != EINTR)
76
0
      error_clnt("read error: %s\n", strerror(errno));
77
0
    return sz;
78
0
  }
79
0
  send_sideband(1, band, buf, sz, LARGE_PACKET_MAX);
80
0
  return sz;
81
0
}
82
83
int cmd_upload_archive(int argc, const char **argv, const char *prefix)
84
0
{
85
0
  struct child_process writer = CHILD_PROCESS_INIT;
86
87
0
  BUG_ON_NON_EMPTY_PREFIX(prefix);
88
89
0
  if (argc == 2 && !strcmp(argv[1], "-h"))
90
0
    usage(upload_archive_usage);
91
92
  /*
93
   * Set up sideband subprocess.
94
   *
95
   * We (parent) monitor and read from child, sending its fd#1 and fd#2
96
   * multiplexed out to our fd#1.  If the child dies, we tell the other
97
   * end over channel #3.
98
   */
99
0
  writer.out = writer.err = -1;
100
0
  writer.git_cmd = 1;
101
0
  strvec_push(&writer.args, "upload-archive--writer");
102
0
  strvec_pushv(&writer.args, argv + 1);
103
0
  if (start_command(&writer)) {
104
0
    int err = errno;
105
0
    packet_write_fmt(1, "NACK unable to spawn subprocess\n");
106
0
    die("upload-archive: %s", strerror(err));
107
0
  }
108
109
0
  packet_write_fmt(1, "ACK\n");
110
0
  packet_flush(1);
111
112
0
  while (1) {
113
0
    struct pollfd pfd[2];
114
115
0
    pfd[0].fd = writer.out;
116
0
    pfd[0].events = POLLIN;
117
0
    pfd[1].fd = writer.err;
118
0
    pfd[1].events = POLLIN;
119
0
    if (poll(pfd, 2, -1) < 0) {
120
0
      if (errno != EINTR) {
121
0
        error_errno("poll failed resuming");
122
0
        sleep(1);
123
0
      }
124
0
      continue;
125
0
    }
126
0
    if (pfd[1].revents & POLLIN)
127
      /* Status stream ready */
128
0
      if (process_input(pfd[1].fd, 2))
129
0
        continue;
130
0
    if (pfd[0].revents & POLLIN)
131
      /* Data stream ready */
132
0
      if (process_input(pfd[0].fd, 1))
133
0
        continue;
134
135
0
    if (finish_command(&writer))
136
0
      error_clnt("%s", deadchild);
137
0
    packet_flush(1);
138
0
    break;
139
0
  }
140
0
  return 0;
141
0
}