xref: /haiku/src/bin/listattr.cpp (revision fa66a805cce4fd4e4fc501ed6e22c0ed684fab9a)
1 /*
2  * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2002, Ryan Fleet.
4  *
5  * Distributed under the terms of the MIT license.
6  */
7 
8 
9 #include <String.h>
10 #include <TypeConstants.h>
11 #include <Mime.h>
12 
13 #include <fs_attr.h>
14 
15 #include <ctype.h>
16 #include <string.h>
17 #include <stdio.h>
18 
19 
20 /*!	Dumps the contents of the attribute in the form of raw data. This view
21 	is used for the type B_RAW_TYPE, for custom types and for any type that
22 	is not directly supported by the utility "addattr".
23 */
24 static void
25 dump_raw_data(const char *buffer, size_t size)
26 {
27 	const uint32 kChunkSize = 16;
28 	uint32 dumpPosition = 0;
29 
30 	while (dumpPosition < size) {
31 		// Position for this line
32 		printf("\t%04lx: ", dumpPosition);
33 
34 		// Print the bytes in form of hexadecimal numbers
35 		for (uint32 i = 0; i < kChunkSize; i++) {
36 			if (dumpPosition + i < size) {
37 				printf("%02x ", (uint8)buffer[dumpPosition + i]);
38 			} else
39 				printf("   ");
40 		}
41 
42 		// Print the bytes in form of printable characters
43 		// (whenever possible)
44 		printf(" ");
45 		for (uint32 i = 0; i < kChunkSize; i++) {
46 			if (dumpPosition < size) {
47 				char c = buffer[dumpPosition];
48 				putchar(isgraph(c) ? c : '.');
49 			} else
50 				putchar(' ');
51 
52 			dumpPosition++;
53 		}
54 		printf("\n");
55 	}
56 }
57 
58 
59 static void
60 show_attr_contents(BNode& node, const char* attribute, const attr_info& info)
61 {
62 	// limit size of the attribute, only the first kLimit byte will make it on
63 	// screen
64 	int kLimit = 256;
65 	bool cut = false;
66 	off_t size = info.size;
67 	if (size > kLimit) {
68 		size = kLimit;
69 		cut = true;
70 	}
71 
72 	char buffer[kLimit];
73 	ssize_t bytesRead = node.ReadAttr(attribute, info.type, 0, buffer, size);
74 	if (bytesRead != size) {
75 		fprintf(stderr, "Could only read %lld bytes from attribute!\n",
76 			size);
77 		return;
78 	}
79 
80 	switch (info.type) {
81 		case B_INT8_TYPE:
82 			printf("%d\n", *((int8 *)buffer));
83 			break;
84 		case B_UINT8_TYPE:
85 			printf("%u\n", *((uint8 *)buffer));
86 			break;
87 		case B_INT16_TYPE:
88 			printf("%d\n", *((int16 *)buffer));
89 			break;
90 		case B_UINT16_TYPE:
91 			printf("%u\n", *((uint16 *)buffer));
92 			break;
93 		case B_INT32_TYPE:
94 			printf("%ld\n", *((int32 *)buffer));
95 			break;
96 		case B_UINT32_TYPE:
97 			printf("%lu\n", *((uint32 *)buffer));
98 			break;
99 		case B_INT64_TYPE:
100 			printf("%lld\n", *((int64 *)buffer));
101 			break;
102 		case B_UINT64_TYPE:
103 			printf("%llu\n", *((uint64 *)buffer));
104 			break;
105 		case B_FLOAT_TYPE:
106 			printf("%f\n", *((float *)buffer));
107 			break;
108 		case B_DOUBLE_TYPE:
109 			printf("%f\n", *((double *)buffer));
110 			break;
111 		case B_BOOL_TYPE:
112 			printf("%d\n", *((unsigned char *)buffer));
113 			break;
114 		case B_STRING_TYPE:
115 		case B_MIME_STRING_TYPE:
116 		case 'MSIG':
117 		case 'MSDC':
118 		case 'MPTH':
119 			printf("%s\n", buffer);
120 			break;
121 
122 		case B_MESSAGE_TYPE:
123 		{
124 			BMessage message;
125 			if (!cut && message.Unflatten(buffer) == B_OK) {
126 				putchar('\n');
127 				message.PrintToStream();
128 				putchar('\n');
129 				break;
130 			}
131 			// supposed to fall through
132 		}
133 
134 		default:
135 			// The rest of the attributes types are displayed as raw data
136 			putchar('\n');
137 			dump_raw_data(buffer, size);
138 			putchar('\n');
139 			break;
140 	}
141 }
142 
143 
144 static const char *
145 get_type(type_code type)
146 {
147 	static char buffer[32];
148 
149 	switch (type) {
150 		case B_MIME_STRING_TYPE:
151 			return "MIME String";
152 		case B_RAW_TYPE:
153 			return "Raw Data";
154 
155 		case B_STRING_TYPE:
156 			return "Text";
157 		case B_INT64_TYPE:
158 			return "Int-64";
159 		case B_UINT64_TYPE:
160 			return "Uint-64";
161 		case B_INT32_TYPE:
162 			return "Int-32";
163 		case B_UINT32_TYPE:
164 			return "Uint-32";
165 		case B_INT16_TYPE:
166 			return "Int-16";
167 		case B_UINT16_TYPE:
168 			return "Uint-16";
169 		case B_INT8_TYPE:
170 			return "Int-8";
171 		case B_UINT8_TYPE:
172 			return "Uint-8";
173 		case B_BOOL_TYPE:
174 			return "Boolean";
175 		case B_FLOAT_TYPE:
176 			return "Float";
177 		case B_DOUBLE_TYPE:
178 			return "Double";
179 
180 		case B_MINI_ICON_TYPE:
181 			return "Mini Icon";
182 		case B_LARGE_ICON_TYPE:
183 			return "Icon";
184 
185 		default:
186 		{
187 			int32 missed = 0, shift = 24;
188 			uint8 value[4];
189 			for (int32 i = 0; i < 4; i++, shift -= 8) {
190 				value[i] = uint8(type >> shift);
191 				if (value[i] < ' ' || value[i] > 127) {
192 					value[i] = '.';
193 					missed++;
194 				}
195 			}
196 
197 			if (missed < 2) {
198 				sprintf(buffer, "'%c%c%c%c'", value[0], value[1], value[2],
199 					value[3]);
200 			} else
201 				sprintf(buffer, "0x%08lx", type);
202 
203 			return buffer;
204 		}
205 	}
206 }
207 
208 
209 int
210 main(int argc, char *argv[])
211 {
212 	const char *program = strrchr(argv[0], '/');
213 	if (program == NULL)
214 		program = argv[0];
215 	else
216 		program++;
217 
218 	bool printContents = false;
219 
220 	if (argc > 2 && (!strcmp(argv[1], "--long") || !strcmp(argv[1], "-l"))) {
221 		printContents = true;
222 		argc--;
223 		argv++;
224 	}
225 
226 	if (argc < 2 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
227 		printf("usage: %s [-l|--long] 'filename' ['filename' ...]\n"
228 			"  -l, --long  Shows the attribute contents as well.\n", program);
229 		return argc == 2 ? 0 : 1;
230 	}
231 
232 	off_t total = 0;
233 
234 	for (int i = 1; i < argc; ++i) {
235 		BNode node(argv[i]);
236 
237 		status_t status = node.InitCheck();
238 		if (status < B_OK) {
239 			fprintf(stderr, "%s: initialization failed for \"%s\": %s\n",
240 				program, argv[i], strerror(status));
241 			return 0;
242 		}
243 
244 		printf("File: %s\n", argv[i]);
245 
246 		const int kTypeWidth = 12;
247 		const int kSizeWidth = 10;
248 		const int kNameWidth = 36;
249 		const int kContentsWidth = 21;
250 		printf("%*s %*s  %-*s%s\n", kTypeWidth, "Type", kSizeWidth, "Size",
251 			kNameWidth, "Name", printContents ? "Contents" : "");
252 
253 		BString separator;
254 		separator.SetTo('-', kTypeWidth + kSizeWidth + kNameWidth
255 			+ (printContents ? kContentsWidth : 0));
256 		puts(separator.String());
257 
258 		char name[B_ATTR_NAME_LENGTH];
259 		while (node.GetNextAttrName(name) == B_OK) {
260 			attr_info attrInfo;
261 
262 			status = node.GetAttrInfo(name, &attrInfo);
263 			if (status >= B_OK) {
264 				printf("%*s", kTypeWidth, get_type(attrInfo.type));
265 				printf("% *Li  ", kSizeWidth, attrInfo.size);
266 				printf("\"%s\"", name);
267 
268 				if (printContents) {
269 					// padding
270 					int length = kNameWidth - 2 - strlen(name);
271 					if (length > 0)
272 						printf("%*s", length, "");
273 
274 					show_attr_contents(node, name, attrInfo);
275 				} else
276 					putchar('\n');
277 
278 				total += attrInfo.size;
279 			} else {
280 				fprintf(stderr, "%s: stat failed for \"%s\": %s\n",
281 					program, name, strerror(status));
282 			}
283 		}
284 	}
285 
286 	printf("\n%Ld bytes total in attributes.\n", total);
287 	return 0;
288 }
289