/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 | | |