Branch data Line data Source code
1 : : #include <stdlib.h>
2 : : #include <unistd.h>
3 : : #include <errno.h>
4 : : #include <string.h>
5 : : #include <sys/types.h>
6 : : #include <sys/stat.h>
7 : :
8 : : #include "crtools.h"
9 : : #include "file-ids.h"
10 : : #include "mount.h"
11 : : #include "files.h"
12 : : #include "image.h"
13 : : #include "list.h"
14 : : #include "util.h"
15 : : #include "atomic.h"
16 : :
17 : : #include "protobuf.h"
18 : : #include "protobuf/regfile.pb-c.h"
19 : : #include "protobuf/remap-file-path.pb-c.h"
20 : :
21 : : #include "files-reg.h"
22 : :
23 : : /*
24 : : * Ghost files are those not visible from the FS. Dumping them is
25 : : * nasty and the only way we have -- just carry its contents with
26 : : * us. Any brave soul to implement link unlinked file back?
27 : : */
28 : : struct ghost_file {
29 : : struct list_head list;
30 : : u32 id;
31 : :
32 : : u32 dev;
33 : : u32 ino;
34 : :
35 : : struct file_remap remap;
36 : : };
37 : :
38 : : static u32 ghost_file_ids = 1;
39 : : static LIST_HEAD(ghost_files);
40 : :
41 : : static mutex_t *ghost_file_mutex;
42 : :
43 : : /*
44 : : * This constant is selected without any calculations. Just do not
45 : : * want to pick up too big files with us in the image.
46 : : */
47 : : #define MAX_GHOST_FILE_SIZE (1 * 1024 * 1024)
48 : :
49 : 25 : static int open_remap_ghost(struct reg_file_info *rfi,
50 : : RemapFilePathEntry *rfe)
51 : : {
52 : : struct ghost_file *gf;
53 : 25 : GhostFileEntry *gfe = NULL;
54 : : int gfd, ifd, ghost_flags;
55 : :
56 : 25 : rfe->remap_id &= ~REMAP_GHOST;
57 [ + + ]: 25 : list_for_each_entry(gf, &ghost_files, list)
58 [ - + ]: 8 : if (gf->id == rfe->remap_id)
59 : : goto gf_found;
60 : :
61 : : /*
62 : : * Ghost not found. We will create one in the same dir
63 : : * as the very first client of it thus resolving any
64 : : * issues with cross-device links.
65 : : */
66 : :
67 : 17 : pr_info("Opening ghost file %#x for %s\n", rfe->remap_id, rfi->path);
68 : :
69 : 17 : gf = shmalloc(sizeof(*gf));
70 [ + - ]: 17 : if (!gf)
71 : : return -1;
72 [ - + ]: 17 : gf->remap.path = xmalloc(PATH_MAX);
73 [ + - ]: 17 : if (!gf->remap.path)
74 : : goto err;
75 : :
76 : 17 : ifd = open_image_ro(CR_FD_GHOST_FILE, rfe->remap_id);
77 [ + - ]: 17 : if (ifd < 0)
78 : : goto err;
79 : :
80 [ + - ]: 17 : if (pb_read_one(ifd, &gfe, PB_GHOST_FILE) < 0)
81 : : goto close_ifd;
82 : :
83 : : /*
84 : : * For old formats where optional has_[dev|ino] is
85 : : * not present we will have zeros here which is quite
86 : : * a sign for "absent" fields.
87 : : */
88 : 17 : gf->dev = gfe->dev;
89 : 17 : gf->ino = gfe->ino;
90 : :
91 : 17 : snprintf(gf->remap.path, PATH_MAX, "%s.cr.%x.ghost", rfi->path, rfe->remap_id);
92 : :
93 [ + + ]: 17 : if (S_ISFIFO(gfe->mode)) {
94 [ - + ]: 3 : if (mknod(gf->remap.path, gfe->mode, 0)) {
95 : 0 : pr_perror("Can't create node for ghost file\n");
96 : : goto close_ifd;
97 : : }
98 : : ghost_flags = O_RDWR; /* To not block */
99 : : } else
100 : : ghost_flags = O_WRONLY | O_CREAT | O_EXCL;
101 : :
102 : 17 : gfd = open(gf->remap.path, ghost_flags, gfe->mode);
103 [ - + ]: 17 : if (gfd < 0) {
104 : 0 : pr_perror("Can't open ghost file");
105 : : goto close_ifd;
106 : : }
107 : :
108 [ - + ]: 17 : if (fchown(gfd, gfe->uid, gfe->gid) < 0) {
109 : 0 : pr_perror("Can't reset user/group on ghost %#x\n", rfe->remap_id);
110 : : goto close_all;
111 : : }
112 : :
113 [ + + ]: 17 : if (S_ISREG(gfe->mode)) {
114 [ + - ]: 14 : if (copy_file(ifd, gfd, 0) < 0)
115 : : goto close_all;
116 : : }
117 : :
118 : 17 : ghost_file_entry__free_unpacked(gfe, NULL);
119 : 17 : close(ifd);
120 : 17 : close(gfd);
121 : :
122 : 17 : gf->id = rfe->remap_id;
123 : 17 : gf->remap.users = 0;
124 : 17 : list_add_tail(&gf->list, &ghost_files);
125 : : gf_found:
126 : 25 : gf->remap.users++;
127 : 25 : rfi->remap = &gf->remap;
128 : : return 0;
129 : :
130 : : close_all:
131 : 0 : close_safe(&gfd);
132 : : close_ifd:
133 : 0 : close_safe(&ifd);
134 : : err:
135 [ # # ]: 0 : if (gfe)
136 : 0 : ghost_file_entry__free_unpacked(gfe, NULL);
137 [ # # ]: 0 : xfree(gf->remap.path);
138 : 25 : shfree_last(gf);
139 : : return -1;
140 : : }
141 : :
142 : 3 : static int open_remap_linked(struct reg_file_info *rfi,
143 : : RemapFilePathEntry *rfe)
144 : : {
145 : : struct file_remap *rm;
146 : : struct file_desc *rdesc;
147 : : struct reg_file_info *rrfi;
148 : :
149 : 3 : rdesc = find_file_desc_raw(FD_TYPES__REG, rfe->remap_id);
150 [ - + ]: 3 : if (!rdesc) {
151 : 0 : pr_err("Can't find target file %x\n", rfe->remap_id);
152 : : return -1;
153 : : }
154 : :
155 [ - + ]: 3 : rm = xmalloc(sizeof(*rm));
156 [ + - ]: 3 : if (!rm)
157 : : return -1;
158 : :
159 : 3 : rrfi = container_of(rdesc, struct reg_file_info, d);
160 : 3 : pr_info("Remapped %s -> %s\n", rfi->path, rrfi->path);
161 : :
162 : 3 : rm->path = rrfi->path;
163 : 3 : rm->users = 1;
164 : 3 : rfi->remap = rm;
165 : : return 0;
166 : : }
167 : :
168 : 355 : static int collect_remaps(void)
169 : : {
170 : 355 : int fd, ret = 0;
171 : :
172 : 355 : fd = open_image_ro(CR_FD_REMAP_FPATH);
173 [ + - ]: 355 : if (fd < 0)
174 : : return -1;
175 : :
176 : : while (1) {
177 : 383 : RemapFilePathEntry *rfe = NULL;
178 : : struct file_desc *fdesc;
179 : : struct reg_file_info *rfi;
180 : :
181 : 383 : ret = pb_read_one_eof(fd, &rfe, PB_REMAP_FPATH);
182 [ + + ]: 383 : if (ret <= 0)
183 : : break;
184 : :
185 : 28 : ret = -1;
186 : 28 : fdesc = find_file_desc_raw(FD_TYPES__REG, rfe->orig_id);
187 [ - + ]: 28 : if (fdesc == NULL) {
188 : 0 : pr_err("Remap for non existing file %#x\n",
189 : : rfe->orig_id);
190 : 0 : goto tail;
191 : : }
192 : :
193 : 28 : rfi = container_of(fdesc, struct reg_file_info, d);
194 : 28 : pr_info("Configuring remap %#x -> %#x\n", rfi->rfe->id, rfe->remap_id);
195 : :
196 [ + + ]: 28 : if (rfe->remap_id & REMAP_GHOST)
197 : 25 : ret = open_remap_ghost(rfi, rfe);
198 : : else
199 : 3 : ret = open_remap_linked(rfi, rfe);
200 : : tail:
201 : 28 : remap_file_path_entry__free_unpacked(rfe, NULL);
202 [ + - ]: 28 : if (ret)
203 : : break;
204 : 28 : }
205 : :
206 : 355 : close(fd);
207 : 355 : return ret;
208 : : }
209 : :
210 : 10 : static int dump_ghost_file(int _fd, u32 id, const struct stat *st)
211 : : {
212 : : int img;
213 : 10 : GhostFileEntry gfe = GHOST_FILE_ENTRY__INIT;
214 : : char lpath[32];
215 : :
216 : 10 : pr_info("Dumping ghost file contents (id %#x)\n", id);
217 : :
218 : 10 : img = open_image(CR_FD_GHOST_FILE, O_DUMP, id);
219 [ + - ]: 10 : if (img < 0)
220 : : return -1;
221 : :
222 : 10 : gfe.uid = st->st_uid;
223 : 10 : gfe.gid = st->st_gid;
224 : 10 : gfe.mode = st->st_mode;
225 : :
226 : 10 : gfe.has_dev = gfe.has_ino = true;
227 : 10 : gfe.dev = MKKDEV(MAJOR(st->st_dev), MINOR(st->st_dev));
228 : 10 : gfe.ino = st->st_ino;
229 : :
230 [ + - ]: 10 : if (pb_write_one(img, &gfe, PB_GHOST_FILE))
231 : : return -1;
232 : :
233 [ + + ]: 10 : if (S_ISREG(st->st_mode)) {
234 : : int fd;
235 : :
236 : : /*
237 : : * Reopen file locally since it may have no read
238 : : * permissions when drained
239 : : */
240 : 8 : snprintf(lpath, sizeof(lpath), "/proc/self/fd/%d", _fd);
241 : 8 : fd = open(lpath, O_RDONLY);
242 [ - + ]: 8 : if (fd < 0) {
243 : 0 : pr_perror("Can't open ghost original file");
244 : : return -1;
245 : : }
246 [ + - ]: 8 : if (copy_file(fd, img, st->st_size))
247 : : return -1;
248 : :
249 : 8 : close(fd);
250 : : }
251 : :
252 : 10 : close(img);
253 : : return 0;
254 : : }
255 : :
256 : 2 : void remap_put(struct file_remap *remap)
257 : : {
258 : 2 : mutex_lock(ghost_file_mutex);
259 [ - + ]: 2 : if (--remap->users == 0) {
260 : 0 : pr_info("Unlink the ghost %s\n", remap->path);
261 : 0 : unlink(remap->path);
262 : : }
263 : 2 : mutex_unlock(ghost_file_mutex);
264 : 2 : }
265 : :
266 : 6 : struct file_remap *lookup_ghost_remap(u32 dev, u32 ino)
267 : : {
268 : : struct ghost_file *gf;
269 : :
270 : 6 : mutex_lock(ghost_file_mutex);
271 [ + + ]: 9 : list_for_each_entry(gf, &ghost_files, list) {
272 [ + - ][ + + ]: 6 : if (gf->dev == dev && gf->ino == ino) {
273 : 3 : gf->remap.users++;
274 : 3 : mutex_unlock(ghost_file_mutex);
275 : 3 : return &gf->remap;
276 : : }
277 : : }
278 : 3 : mutex_unlock(ghost_file_mutex);
279 : :
280 : 6 : return NULL;
281 : : }
282 : :
283 : 14 : static int dump_ghost_remap(char *path, const struct stat *st, int lfd, u32 id)
284 : : {
285 : : struct ghost_file *gf;
286 : 14 : RemapFilePathEntry rpe = REMAP_FILE_PATH_ENTRY__INIT;
287 : :
288 : 14 : pr_info("Dumping ghost file for fd %d id %#x\n", lfd, id);
289 : :
290 [ - + ]: 14 : if (st->st_size > MAX_GHOST_FILE_SIZE) {
291 : 0 : pr_err("Can't dump ghost file %s of %lu size\n",
292 : : path, st->st_size);
293 : : return -1;
294 : : }
295 : :
296 [ + + ]: 14 : list_for_each_entry(gf, &ghost_files, list)
297 [ + - ][ - + ]: 4 : if ((gf->dev == st->st_dev) && (gf->ino == st->st_ino))
298 : : goto dump_entry;
299 : :
300 [ - + ]: 10 : gf = xmalloc(sizeof(*gf));
301 [ + - ]: 10 : if (gf == NULL)
302 : : return -1;
303 : :
304 : 10 : gf->dev = st->st_dev;
305 : 10 : gf->ino = st->st_ino;
306 : 10 : gf->id = ghost_file_ids++;
307 : 10 : list_add_tail(&gf->list, &ghost_files);
308 : :
309 [ + - ]: 10 : if (dump_ghost_file(lfd, gf->id, st))
310 : : return -1;
311 : :
312 : : dump_entry:
313 : 14 : rpe.orig_id = id;
314 : 14 : rpe.remap_id = gf->id | REMAP_GHOST;
315 : :
316 : 14 : return pb_write_one(fdset_fd(glob_fdset, CR_FD_REMAP_FPATH),
317 : : &rpe, PB_REMAP_FPATH);
318 : : }
319 : :
320 : 2 : static int create_link_remap(char *path, int len, int lfd, u32 *idp)
321 : : {
322 : : char link_name[PATH_MAX], *tmp;
323 : 2 : RegFileEntry rfe = REG_FILE_ENTRY__INIT;
324 : 2 : FownEntry fwn = FOWN_ENTRY__INIT;
325 : :
326 [ - + ]: 2 : if (!opts.link_remap_ok) {
327 : 0 : pr_err("Can't create link remap for %s. "
328 : : "Use " LREMAP_PARAM " option.\n", path);
329 : : return -1;
330 : : }
331 : :
332 : : /*
333 : : * Linked remapping -- we create a hard link on a removed file
334 : : * in the directory original file used to sit.
335 : : *
336 : : * Bad news is than we can't easily open lfd's parent dir. Thus
337 : : * we have to just generate an absolute path and use it. The linkat
338 : : * will fail if we chose the bad one.
339 : : */
340 : :
341 : 2 : link_name[0] = '.';
342 : 2 : memcpy(link_name + 1, path, len);
343 : 2 : tmp = link_name + len + 1;
344 [ + + ]: 60 : while (*tmp != '/') {
345 [ - + ]: 58 : BUG_ON(tmp == link_name);
346 : 58 : tmp--;
347 : : }
348 : :
349 : 2 : rfe.id = *idp = fd_id_generate_special();
350 : 2 : rfe.flags = 0;
351 : 2 : rfe.pos = 0;
352 : 2 : rfe.fown = &fwn;
353 : 2 : rfe.name = link_name + 1;
354 : :
355 : : /* Any 'unique' name works here actually. Remap works by reg-file ids. */
356 : 2 : sprintf(tmp + 1, "link_remap.%d", rfe.id);
357 : :
358 [ - + ]: 2 : if (linkat(lfd, "", mntns_root, link_name, AT_EMPTY_PATH) < 0) {
359 : 0 : pr_perror("Can't link remap to %s", path);
360 : : return -1;
361 : : }
362 : :
363 : 2 : return pb_write_one(fdset_fd(glob_fdset, CR_FD_REG_FILES), &rfe, PB_REG_FILES);
364 : : }
365 : :
366 : 2 : static int dump_linked_remap(char *path, int len, const struct stat *ost, int lfd, u32 id)
367 : : {
368 : : u32 lid;
369 : 2 : RemapFilePathEntry rpe = REMAP_FILE_PATH_ENTRY__INIT;
370 : :
371 [ + - ]: 2 : if (create_link_remap(path, len, lfd, &lid))
372 : : return -1;
373 : :
374 : 2 : rpe.orig_id = id;
375 : 2 : rpe.remap_id = lid;
376 : :
377 : 2 : return pb_write_one(fdset_fd(glob_fdset, CR_FD_REMAP_FPATH),
378 : : &rpe, PB_REMAP_FPATH);
379 : : }
380 : :
381 : 4892 : static int check_path_remap(char *rpath, int plen, const struct stat *ost, int lfd, u32 id)
382 : : {
383 : : int ret;
384 : : struct stat pst;
385 : :
386 [ + + ]: 4892 : if (ost->st_nlink == 0)
387 : : /*
388 : : * Unpleasant, but easy case. File is completely invisible
389 : : * from the FS. Just dump its contents and that's it. But
390 : : * be careful whether anybody still has any of its hardlinks
391 : : * also open.
392 : : */
393 : 14 : return dump_ghost_remap(rpath + 1, ost, lfd, id);
394 : :
395 : 9756 : ret = fstatat(mntns_root, rpath, &pst, 0);
396 [ + + ]: 4878 : if (ret < 0) {
397 : : /*
398 : : * FIXME linked file, but path is not accessible (unless any
399 : : * other error occurred). We can create a temporary link to it
400 : : * uning linkat with AT_EMPTY_PATH flag and remap it to this
401 : : * name.
402 : : */
403 : :
404 [ + - ]: 2 : if (errno == ENOENT)
405 : 2 : return dump_linked_remap(rpath + 1, plen - 1, ost, lfd, id);
406 : :
407 : 0 : pr_perror("Can't stat path");
408 : : return -1;
409 : : }
410 : :
411 [ + + ][ - + ]: 4876 : if ((pst.st_ino != ost->st_ino) || (pst.st_dev != ost->st_dev)) {
412 [ + - ][ + - ]: 1 : if (opts.evasive_devices &&
413 [ - + ]: 1 : (S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
414 : 1 : pst.st_rdev == ost->st_rdev)
415 : : return 0;
416 : : /*
417 : : * FIXME linked file, but the name we see it by is reused
418 : : * by somebody else.
419 : : */
420 : 4892 : pr_err("Unaccessible path opened %u:%u, need %u:%u\n",
421 : : (int)pst.st_dev, (int)pst.st_ino,
422 : : (int)ost->st_dev, (int)ost->st_ino);
423 : : return -1;
424 : : }
425 : :
426 : : /*
427 : : * File is linked and visible by the name it is opened by
428 : : * this task. Go ahead and dump it.
429 : : */
430 : : return 0;
431 : : }
432 : :
433 : 4892 : int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p)
434 : : {
435 : : char fd_str[128];
436 : 4892 : char rpath[PATH_MAX + 1] = ".", *path = rpath + 1;
437 : : int len, rfd;
438 : :
439 : 4892 : RegFileEntry rfe = REG_FILE_ENTRY__INIT;
440 : :
441 : 4892 : snprintf(fd_str, sizeof(fd_str), "/proc/self/fd/%d", lfd);
442 : 4892 : len = readlink(fd_str, path, sizeof(rpath) - 2);
443 [ - + ]: 4892 : if (len < 0) {
444 : 0 : pr_perror("Can't readlink %s", fd_str);
445 : : return len;
446 : : }
447 : :
448 : 4892 : path[len] = '\0';
449 : 4892 : pr_info("Dumping path for %d fd via self %d [%s]\n",
450 : : p->fd, lfd, path);
451 : :
452 [ + - ]: 4892 : if (check_path_remap(rpath, len, &p->stat, lfd, id))
453 : : return -1;
454 : :
455 : 4892 : rfe.id = id;
456 : 4892 : rfe.flags = p->flags;
457 : 4892 : rfe.pos = p->pos;
458 : 4892 : rfe.fown = (FownEntry *)&p->fown;
459 : 4892 : rfe.name = path;
460 : :
461 : 4892 : rfd = fdset_fd(glob_fdset, CR_FD_REG_FILES);
462 : :
463 : 4892 : return pb_write_one(rfd, &rfe, PB_REG_FILES);
464 : : }
465 : :
466 : : static const struct fdtype_ops regfile_ops = {
467 : : .type = FD_TYPES__REG,
468 : : .dump = dump_one_reg_file,
469 : : };
470 : :
471 : 1125 : int dump_reg_file(struct fd_parms *p, int lfd,
472 : : const struct cr_fdset *cr_fdset)
473 : : {
474 : 1125 : return do_dump_gen_file(p, lfd, ®file_ops, cr_fdset);
475 : : }
476 : :
477 : 6990 : static int open_path(struct file_desc *d,
478 : : int(*open_cb)(struct reg_file_info *, void *), void *arg)
479 : : {
480 : : struct reg_file_info *rfi;
481 : : int tmp;
482 : :
483 : 6990 : rfi = container_of(d, struct reg_file_info, d);
484 : :
485 [ + + ]: 6990 : if (rfi->remap) {
486 : 16 : mutex_lock(ghost_file_mutex);
487 [ - + ]: 16 : if (link(rfi->remap->path, rfi->path) < 0) {
488 : 0 : pr_perror("Can't link %s -> %s\n",
489 : : rfi->remap->path, rfi->path);
490 : 0 : return -1;
491 : : }
492 : : }
493 : :
494 : 6990 : tmp = open_cb(rfi, arg);
495 [ - + ]: 6990 : if (tmp < 0) {
496 : 0 : pr_perror("Can't open file %s", rfi->path);
497 : 0 : return -1;
498 : : }
499 : :
500 [ + + ]: 6990 : if (rfi->remap) {
501 : 16 : unlink(rfi->path);
502 [ - + ]: 16 : BUG_ON(!rfi->remap->users);
503 [ + + ]: 16 : if (--rfi->remap->users == 0) {
504 : 12 : pr_info("Unlink the ghost %s\n", rfi->remap->path);
505 : 12 : unlink(rfi->remap->path);
506 : : }
507 : 16 : mutex_unlock(ghost_file_mutex);
508 : : }
509 : :
510 [ + - ]: 6990 : if (restore_fown(tmp, rfi->rfe->fown))
511 : : return -1;
512 : :
513 : 6990 : return tmp;
514 : : }
515 : :
516 : 6436 : int open_path_by_id(u32 id, int (*open_cb)(struct reg_file_info *, void *), void *arg)
517 : : {
518 : : struct file_desc *fd;
519 : :
520 : 6436 : fd = find_file_desc_raw(FD_TYPES__REG, id);
521 [ - + ]: 6436 : if (fd == NULL) {
522 : 0 : pr_perror("Can't find regfile for %#x\n", id);
523 : 0 : return -1;
524 : : }
525 : :
526 : 6436 : return open_path(fd, open_cb, arg);
527 : : }
528 : :
529 : 6976 : static int do_open_reg(struct reg_file_info *rfi, void *arg)
530 : : {
531 : : int fd;
532 : :
533 : 6976 : fd = open(rfi->path, rfi->rfe->flags);
534 [ - + ]: 6976 : if (fd < 0) {
535 : 0 : pr_perror("Can't open file on restore");
536 : 0 : return fd;
537 : : }
538 : :
539 [ - + ]: 6976 : if (lseek(fd, rfi->rfe->pos, SEEK_SET) < 0) {
540 : 0 : pr_perror("Can't restore file pos");
541 : 6976 : return -1;
542 : : }
543 : :
544 : : return fd;
545 : : }
546 : :
547 : 554 : static int open_fe_fd(struct file_desc *fd)
548 : : {
549 : 554 : return open_path(fd, do_open_reg, NULL);
550 : : }
551 : :
552 : 6422 : int open_reg_by_id(u32 id)
553 : : {
554 : 6422 : return open_path_by_id(id, do_open_reg, NULL);
555 : : }
556 : :
557 : : static struct file_desc_ops reg_desc_ops = {
558 : : .type = FD_TYPES__REG,
559 : : .open = open_fe_fd,
560 : : };
561 : :
562 : 19060 : static int collect_one_regfile(void *o, ProtobufCMessage *base)
563 : : {
564 : 19060 : struct reg_file_info *rfi = o;
565 : :
566 : 19060 : rfi->rfe = pb_msg(base, RegFileEntry);
567 : 19060 : rfi->path = rfi->rfe->name;
568 : 19060 : rfi->remap = NULL;
569 : :
570 : 19060 : pr_info("Collected [%s] ID %#x\n", rfi->path, rfi->rfe->id);
571 : 19060 : file_desc_add(&rfi->d, rfi->rfe->id, ®_desc_ops);
572 : :
573 : 19060 : return 0;
574 : : }
575 : :
576 : 355 : int prepare_shared_reg_files(void)
577 : : {
578 : 355 : ghost_file_mutex = shmalloc(sizeof(*ghost_file_mutex));
579 [ + - ]: 355 : if (!ghost_file_mutex)
580 : : return -1;
581 : :
582 : 355 : mutex_init(ghost_file_mutex);
583 : 355 : return 0;
584 : : }
585 : :
586 : 355 : int collect_reg_files(void)
587 : : {
588 : : int ret;
589 : :
590 : 355 : ret = collect_image(CR_FD_REG_FILES, PB_REG_FILES,
591 : : sizeof(struct reg_file_info), collect_one_regfile);
592 [ + - ]: 355 : if (!ret)
593 : 355 : ret = collect_remaps();
594 : :
595 : 355 : return ret;
596 : 84 : }
|