New upstream version 18.08
[deb_dpdk.git] / test / test / resource.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016 RehiveTech. All rights reserved.
3  */
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <sys/queue.h>
9
10 #include <rte_debug.h>
11
12 #include "resource.h"
13
14 struct resource_list resource_list = TAILQ_HEAD_INITIALIZER(resource_list);
15
16 size_t resource_size(const struct resource *r)
17 {
18         return r->end - r->begin;
19 }
20
21 const struct resource *resource_find(const char *name)
22 {
23         struct resource *r;
24
25         TAILQ_FOREACH(r, &resource_list, next) {
26                 RTE_VERIFY(r->name);
27
28                 if (!strcmp(r->name, name))
29                         return r;
30         }
31
32         return NULL;
33 }
34
35 int resource_fwrite(const struct resource *r, FILE *f)
36 {
37         const size_t goal = resource_size(r);
38         size_t total = 0;
39
40         while (total < goal) {
41                 size_t wlen = fwrite(r->begin + total, 1, goal - total, f);
42                 if (wlen == 0) {
43                         perror(__func__);
44                         return -1;
45                 }
46
47                 total += wlen;
48         }
49
50         return 0;
51 }
52
53 int resource_fwrite_file(const struct resource *r, const char *fname)
54 {
55         FILE *f;
56         int ret;
57
58         f = fopen(fname, "w");
59         if (f == NULL) {
60                 perror(__func__);
61                 return -1;
62         }
63
64         ret = resource_fwrite(r, f);
65         fclose(f);
66         return ret;
67 }
68
69 #ifdef RTE_APP_TEST_RESOURCE_TAR
70 #include <archive.h>
71 #include <archive_entry.h>
72
73 static int do_copy(struct archive *r, struct archive *w)
74 {
75         const void *buf;
76         size_t len;
77 #if ARCHIVE_VERSION_NUMBER >= 3000000
78         int64_t off;
79 #else
80         off_t off;
81 #endif
82         int ret;
83
84         while (1) {
85                 ret = archive_read_data_block(r, &buf, &len, &off);
86                 if (ret == ARCHIVE_RETRY)
87                         continue;
88
89                 if (ret == ARCHIVE_EOF)
90                         return 0;
91
92                 if (ret != ARCHIVE_OK)
93                         return ret;
94
95                 do {
96                         ret = archive_write_data_block(w, buf, len, off);
97                         if (ret != ARCHIVE_OK && ret != ARCHIVE_RETRY)
98                                 return ret;
99                 } while (ret != ARCHIVE_OK);
100         }
101 }
102
103 int resource_untar(const struct resource *res)
104 {
105         struct archive *r;
106         struct archive *w;
107         struct archive_entry *e;
108         void *p;
109         int flags = 0;
110         int ret;
111
112         p = malloc(resource_size(res));
113         if (p == NULL)
114                 rte_panic("Failed to malloc %zu B\n", resource_size(res));
115
116         memcpy(p, res->begin, resource_size(res));
117
118         r = archive_read_new();
119         if (r == NULL) {
120                 free(p);
121                 return -1;
122         }
123
124         archive_read_support_format_all(r);
125         archive_read_support_filter_all(r);
126
127         w = archive_write_disk_new();
128         if (w == NULL) {
129                 archive_read_free(r);
130                 free(p);
131                 return -1;
132         }
133
134         flags |= ARCHIVE_EXTRACT_PERM;
135         flags |= ARCHIVE_EXTRACT_FFLAGS;
136         archive_write_disk_set_options(w, flags);
137         archive_write_disk_set_standard_lookup(w);
138
139         ret = archive_read_open_memory(r, p, resource_size(res));
140         if (ret != ARCHIVE_OK)
141                 goto fail;
142
143         while (1) {
144                 ret = archive_read_next_header(r, &e);
145                 if (ret == ARCHIVE_EOF)
146                         break;
147                 if (ret != ARCHIVE_OK)
148                         goto fail;
149
150                 ret = archive_write_header(w, e);
151                 if (ret == ARCHIVE_EOF)
152                         break;
153                 if (ret != ARCHIVE_OK)
154                         goto fail;
155
156                 if (archive_entry_size(e) == 0)
157                         continue;
158
159                 ret = do_copy(r, w);
160                 if (ret != ARCHIVE_OK)
161                         goto fail;
162
163                 ret = archive_write_finish_entry(w);
164                 if (ret != ARCHIVE_OK)
165                         goto fail;
166         }
167
168         archive_write_free(w);
169         archive_read_free(r);
170         free(p);
171         return 0;
172
173 fail:
174         archive_write_free(w);
175         archive_read_free(r);
176         free(p);
177         rte_panic("Failed: %s\n", archive_error_string(r));
178         return -1;
179 }
180
181 int resource_rm_by_tar(const struct resource *res)
182 {
183         struct archive *r;
184         struct archive_entry *e;
185         void *p;
186         int try_again = 1;
187         int attempts = 0;
188         int ret;
189
190         p = malloc(resource_size(res));
191         if (p == NULL)
192                 rte_panic("Failed to malloc %zu B\n", resource_size(res));
193
194         memcpy(p, res->begin, resource_size(res));
195
196         /*
197          * If somebody creates a file somewhere inside the extracted TAR
198          * hierarchy during a test the resource_rm_by_tar might loop
199          * infinitely. We prevent this by adding the attempts counter there.
200          * In normal case, max N iteration is done where N is the depth of
201          * the file-hierarchy.
202          */
203         while (try_again && attempts < 10000) {
204                 r = archive_read_new();
205                 if (r == NULL) {
206                         free(p);
207                         return -1;
208                 }
209
210                 archive_read_support_format_all(r);
211                 archive_read_support_filter_all(r);
212
213                 ret = archive_read_open_memory(r, p, resource_size(res));
214                 if (ret != ARCHIVE_OK) {
215                         fprintf(stderr, "Failed: %s\n",
216                                         archive_error_string(r));
217                         goto fail;
218                 }
219
220                 try_again = 0;
221
222                 while (1) {
223                         ret = archive_read_next_header(r, &e);
224                         if (ret == ARCHIVE_EOF)
225                                 break;
226                         if (ret != ARCHIVE_OK)
227                                 goto fail;
228
229                         ret = remove(archive_entry_pathname(e));
230                         if (ret < 0) {
231                                 switch (errno) {
232                                 case ENOTEMPTY:
233                                 case EEXIST:
234                                         try_again = 1;
235                                         break;
236
237                                 /* should not usually happen: */
238                                 case ENOENT:
239                                 case ENOTDIR:
240                                 case EROFS:
241                                         attempts += 1;
242                                         continue;
243                                 default:
244                                         perror("Failed to remove file");
245                                         goto fail;
246                                 }
247                         }
248                 }
249
250                 archive_read_free(r);
251                 attempts += 1;
252         }
253
254         if (attempts >= 10000) {
255                 fprintf(stderr, "Failed to remove archive\n");
256                 free(p);
257                 return -1;
258         }
259
260         free(p);
261         return 0;
262
263 fail:
264         archive_read_free(r);
265         free(p);
266
267         rte_panic("Failed: %s\n", archive_error_string(r));
268         return -1;
269 }
270
271 #endif /* RTE_APP_TEST_RESOURCE_TAR */
272
273 void resource_register(struct resource *r)
274 {
275         TAILQ_INSERT_TAIL(&resource_list, r, next);
276 }