Coverage Report

Created: 2025-10-13 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libarchive/libarchive/archive_cmdline.c
Line
Count
Source
1
/*-
2
 * Copyright (c) 2012 Michihiro NAKAJIMA 
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
#include "archive_platform.h"
27
28
#ifdef HAVE_STRING_H
29
#  include <string.h>
30
#endif
31
#ifdef HAVE_STDLIB_H
32
#  include <stdlib.h>
33
#endif
34
35
#include "archive.h"
36
#include "archive_cmdline_private.h"
37
#include "archive_string.h"
38
39
static int cmdline_set_path(struct archive_cmdline *, const char *);
40
static int cmdline_add_arg(struct archive_cmdline *, const char *);
41
42
static ssize_t
43
extract_quotation(struct archive_string *as, const char *p)
44
0
{
45
0
  const char *s;
46
47
0
  for (s = p + 1; *s;) {
48
0
    if (*s == '\\') {
49
0
      if (s[1] != '\0') {
50
0
        archive_strappend_char(as, s[1]);
51
0
        s += 2;
52
0
      } else
53
0
        s++;
54
0
    } else if (*s == '"')
55
0
      break;
56
0
    else {
57
0
      archive_strappend_char(as, s[0]);
58
0
      s++;
59
0
    }
60
0
  }
61
0
  if (*s != '"')
62
0
    return (ARCHIVE_FAILED);/* Invalid sequence. */
63
0
  return ((ssize_t)(s + 1 - p));
64
0
}
65
66
static ssize_t
67
get_argument(struct archive_string *as, const char *p)
68
14
{
69
14
  const char *s = p;
70
71
14
  archive_string_empty(as);
72
73
  /* Skip beginning space characters. */
74
20
  while (*s == ' ')
75
6
    s++;
76
  /* Copy non-space characters. */
77
45
  while (*s != '\0' && *s != ' ') {
78
31
    if (*s == '\\') {
79
0
      if (s[1] != '\0') {
80
0
        archive_strappend_char(as, s[1]);
81
0
        s += 2;
82
0
      } else {
83
0
        s++;/* Ignore this character.*/
84
0
        break;
85
0
      }
86
31
    } else if (*s == '"') {
87
0
      ssize_t q = extract_quotation(as, s);
88
0
      if (q < 0)
89
0
        return (ARCHIVE_FAILED);/* Invalid sequence. */
90
0
      s += q;
91
31
    } else {
92
31
      archive_strappend_char(as, s[0]);
93
31
      s++;
94
31
    }
95
31
  }
96
14
  return ((ssize_t)(s - p));
97
14
}
98
99
/*
100
 * Set up command line arguments.
101
 * Returns ARCHIVE_OK if everything okey.
102
 * Returns ARCHIVE_FAILED if there is a lack of the `"' terminator or an
103
 * empty command line.
104
 * Returns ARCHIVE_FATAL if no memory.
105
 */
106
int
107
__archive_cmdline_parse(struct archive_cmdline *data, const char *cmd)
108
4
{
109
4
  struct archive_string as;
110
4
  const char *p;
111
4
  ssize_t al;
112
4
  int r;
113
114
4
  archive_string_init(&as);
115
116
  /* Get first argument as a command path. */
117
4
  al = get_argument(&as, cmd);
118
4
  if (al < 0) {
119
0
    r = ARCHIVE_FAILED;/* Invalid sequence. */
120
0
    goto exit_function;
121
0
  }
122
4
  if (archive_strlen(&as) == 0) {
123
0
    r = ARCHIVE_FAILED;/* An empty command path. */
124
0
    goto exit_function;
125
0
  }
126
4
  r = cmdline_set_path(data, as.s);
127
4
  if (r != ARCHIVE_OK)
128
0
    goto exit_function;
129
4
  p = strrchr(as.s, '/');
130
4
  if (p == NULL)
131
4
    p = as.s;
132
0
  else
133
0
    p++;
134
4
  r = cmdline_add_arg(data, p);
135
4
  if (r != ARCHIVE_OK)
136
0
    goto exit_function;
137
4
  cmd += al;
138
139
10
  for (;;) {
140
10
    al = get_argument(&as, cmd);
141
10
    if (al < 0) {
142
0
      r = ARCHIVE_FAILED;/* Invalid sequence. */
143
0
      goto exit_function;
144
0
    }
145
10
    if (al == 0)
146
4
      break;
147
6
    cmd += al;
148
6
    if (archive_strlen(&as) == 0 && *cmd == '\0')
149
0
      break;
150
6
    r = cmdline_add_arg(data, as.s);
151
6
    if (r != ARCHIVE_OK)
152
0
      goto exit_function;
153
6
  }
154
4
  r = ARCHIVE_OK;
155
4
exit_function:
156
4
  archive_string_free(&as);
157
4
  return (r);
158
4
}
159
160
/*
161
 * Set the program path.
162
 */
163
static int
164
cmdline_set_path(struct archive_cmdline *data, const char *path)
165
4
{
166
4
  char *newptr;
167
168
4
  newptr = realloc(data->path, strlen(path) + 1);
169
4
  if (newptr == NULL)
170
0
    return (ARCHIVE_FATAL);
171
4
  data->path = newptr;
172
4
  strcpy(data->path, path);
173
4
  return (ARCHIVE_OK);
174
4
}
175
176
/*
177
 * Add a argument for the program.
178
 */
179
static int
180
cmdline_add_arg(struct archive_cmdline *data, const char *arg)
181
10
{
182
10
  char **newargv;
183
184
10
  if (data->path == NULL)
185
0
    return (ARCHIVE_FAILED);
186
187
10
  newargv = realloc(data->argv, (data->argc + 2) * sizeof(char *));
188
10
  if (newargv == NULL)
189
0
    return (ARCHIVE_FATAL);
190
10
  data->argv = newargv;
191
10
  data->argv[data->argc] = strdup(arg);
192
10
  if (data->argv[data->argc] == NULL)
193
0
    return (ARCHIVE_FATAL);
194
  /* Set the terminator of argv. */
195
10
  data->argv[++data->argc] = NULL;
196
10
  return (ARCHIVE_OK);
197
10
}
198
199
struct archive_cmdline *
200
__archive_cmdline_allocate(void)
201
4
{
202
4
  return (struct archive_cmdline *)
203
4
    calloc(1, sizeof(struct archive_cmdline));
204
4
}
205
206
/*
207
 * Release the resources.
208
 */
209
int
210
__archive_cmdline_free(struct archive_cmdline *data)
211
4
{
212
213
4
  if (data) {
214
4
    free(data->path);
215
4
    if (data->argv != NULL) {
216
4
      int i;
217
14
      for (i = 0; data->argv[i] != NULL; i++)
218
10
        free(data->argv[i]);
219
4
      free(data->argv);
220
4
    }
221
4
    free(data);
222
4
  }
223
4
  return (ARCHIVE_OK);
224
4
}
225