summaryrefslogtreecommitdiff
path: root/unpack/describe.c
blob: c3166c4b8d14e5ca907d3c402bcbe8610d228d06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
 * describe.c
 *
 * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
 */
#include "rdsquashfs.h"

static int print_name(tree_node_t *n)
{
	char *start, *ptr, *name = fstree_get_path(n);
	int ret;

	if (name == NULL) {
		perror("Recovering file path of tree node");
		return -1;
	}

	ret = canonicalize_name(name);
	assert(ret == 0);

	if (strchr(name, ' ') == NULL && strchr(name, '"') == NULL) {
		fputs(name, stdout);
	} else {
		fputc('"', stdout);

		ptr = strchr(name, '"');

		if (ptr != NULL) {
			start = name;

			do {
				fwrite(start, 1, ptr - start, stdout);
				fputs("\\\"", stdout);
				start = ptr + 1;
				ptr = strchr(start, '"');
			} while (ptr != NULL);

			fputs(start, stdout);
		} else {
			fputs(name, stdout);
		}

		fputc('"', stdout);
	}

	free(name);
	return 0;
}

static void print_perm(tree_node_t *n)
{
	printf(" 0%o %d %d", n->mode & (~S_IFMT), n->uid, n->gid);
}

static int print_simple(const char *type, tree_node_t *n, const char *extra)
{
	printf("%s ", type);
	if (print_name(n))
		return -1;
	print_perm(n);
	if (extra != NULL)
		printf(" %s", extra);
	fputc('\n', stdout);
	return 0;
}

int describe_tree(tree_node_t *root, const char *unpack_root)
{
	tree_node_t *n;

	switch (root->mode & S_IFMT) {
	case S_IFSOCK:
		return print_simple("sock", root, NULL);
	case S_IFLNK:
		return print_simple("slink", root, root->data.slink_target);
	case S_IFIFO:
		return print_simple("pipe", root, NULL);
	case S_IFREG:
		if (unpack_root == NULL)
			return print_simple("file", root, NULL);

		fputs("file ", stdout);
		if (print_name(root))
			return -1;
		print_perm(root);
		printf(" %s/", unpack_root);
		if (print_name(root))
			return -1;
		fputc('\n', stdout);
		break;
	case S_IFCHR:
	case S_IFBLK: {
		char buffer[32];
		sprintf(buffer, "%c %d %d", S_ISCHR(root->mode) ? 'c' : 'b',
		       major(root->data.devno), minor(root->data.devno));
		return print_simple("nod", root, buffer);
	}
	case S_IFDIR:
		if (root->name[0] != '\0') {
			if (print_simple("dir", root, NULL))
				return -1;
		}

		for (n = root->data.dir->children; n != NULL; n = n->next) {
			if (describe_tree(n, unpack_root))
				return -1;
		}
		break;
	}

	return 0;
}