xref: /haiku/src/bin/catattr.cpp (revision f75a7bf508f3156d63a14f8fd77c5e0ca4d08c42)
1 /*
2  * Copyright 2005, Stephan Aßmus, superstippi@yellowbites.com.
3  * Copyright 2004, Axel Dörfler, axeld@pinc-software.de.
4  * Copyright 2002, Sebastian Nozzi.
5  *
6  * Distributed under the terms of the MIT license.
7  */
8 
9 
10 #include <Mime.h>
11 #include <TypeConstants.h>
12 
13 #include <fs_attr.h>
14 
15 #include <ctype.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 
22 
23 /** Used to present the characters in the raw data view */
24 
25 static void
26 putCharOrDot(uchar c)
27 {
28 	putchar(isgraph(c) ? c : '.');
29 }
30 
31 
32 /** Dumps the contents of the attribute in the form of
33  *	raw data. This view is used for the type B_RAW_DATA_TYPE,
34  *	for custom types and for any type that is not directly
35  *	supported by the utility "addattr"
36  */
37 
38 static void
39 dumpRawData(const char *buffer, size_t size)
40 {
41 	const uint32 kChunkSize = 16;
42 	uint32 dumpPosition = 0;
43 
44 	while (dumpPosition < size) {
45 		// Position for this line
46 		printf("0x%06lx:  ", dumpPosition);
47 
48 		// Print the bytes in form of hexadecimal numbers
49 		for (uint32 i = 0; i < kChunkSize; i++) {
50 			if (dumpPosition + i < size) {
51 				printf("%02x ", (uint8)buffer[dumpPosition + i]);
52 			} else
53 				printf("   ");
54 		}
55 
56 		// Print the bytes in form of printable characters
57 		// (whenever possible)
58 		printf("  '");
59 		for (uint32 i = 0; i < kChunkSize; i++) {
60 			if (dumpPosition < size)
61 				putCharOrDot(buffer[dumpPosition]);
62 			else
63 				putchar(' ');
64 
65 			dumpPosition++;
66 		}
67 		printf("'\n");
68 	}
69 }
70 
71 
72 static status_t
73 catAttr(const char *attribute, const char *fileName, bool keepRaw = false)
74 {
75 	int fd = open(fileName, O_RDONLY);
76 	if (fd < 0)
77 		return errno;
78 
79 	attr_info info;
80 	if (fs_stat_attr(fd, attribute, &info) < 0)
81 		return errno;
82 
83 	// limit size of the attribute, only the first 64k will make it on screen
84 	off_t size = info.size;
85 	if (size > 64 * 1024)
86 		size = 64 * 1024;
87 
88 	char* buffer = (char*)malloc(size);
89 	if (!buffer) {
90 		fprintf(stderr, "Could not allocate read buffer!\n");
91 		return B_NO_MEMORY;
92 	}
93 
94 	ssize_t bytesRead = fs_read_attr(fd, attribute, info.type, 0, buffer, size);
95 	if (bytesRead < 0) {
96 		free(buffer);
97 		return errno;
98 	}
99 
100 	if (bytesRead != size) {
101 		fprintf(stderr, "Could only read %ld bytes from attribute!\n", bytesRead);
102 		free(buffer);
103 		return B_ERROR;
104 	}
105 
106 	if (keepRaw) {
107 		off_t pos = 0;
108 		ssize_t written = 0;
109 		while (pos < info.size) {
110 			// write what we have read so far
111 			written = write(STDOUT_FILENO, buffer, bytesRead);
112 			// check for write error
113 			if (written < bytesRead) {
114 				if (written >= 0) {
115 					fprintf(stderr, "Could only write %ld bytes to stream!\n", written);
116 					written = B_ERROR;
117 				} else
118 					fprintf(stderr, "Failed to write to stream: %s\n", strerror(written));
119 				break;
120 			}
121 			// read next chunk of data at pos
122 			pos += bytesRead;
123 			bytesRead = fs_read_attr(fd, attribute, info.type, pos, buffer, size);
124 			// check for read error
125 			if (bytesRead < size && pos + bytesRead < info.size) {
126 				if (bytesRead >= 0)
127 					fprintf(stderr, "Could only read %ld bytes from attribute!\n", bytesRead);
128 				else
129 					fprintf(stderr, "Failed to read from attribute: %s\n", strerror(bytesRead));
130 				written = B_ERROR;
131 				break;
132 			}
133 		}
134 		free(buffer);
135 		if (written > 0)
136 			written = B_OK;
137 		return written;
138 	}
139 
140 	switch (info.type) {
141 		case B_INT8_TYPE:
142 			printf("%s : int8 : %d\n", fileName, *((int8 *)buffer));
143 			break;
144 		case B_UINT8_TYPE:
145 			printf("%s : uint8 : %u\n", fileName, *((uint8 *)buffer));
146 			break;
147 		case B_INT16_TYPE:
148 			printf("%s : int16 : %d\n", fileName, *((int16 *)buffer));
149 			break;
150 		case B_UINT16_TYPE:
151 			printf("%s : uint16 : %u\n", fileName, *((uint16 *)buffer));
152 			break;
153 		case B_INT32_TYPE:
154 			printf("%s : int32 : %ld\n", fileName, *((int32 *)buffer));
155 			break;
156 		case B_UINT32_TYPE:
157 			printf("%s : uint32 : %lu\n", fileName, *((uint32 *)buffer));
158 			break;
159 		case B_INT64_TYPE:
160 			printf("%s : int64 : %Ld\n", fileName, *((int64 *)buffer));
161 			break;
162 		case B_UINT64_TYPE:
163 			printf("%s : uint64 : %Lu\n", fileName, *((uint64 *)buffer));
164 			break;
165 		case B_FLOAT_TYPE:
166 			printf("%s : float : %f\n", fileName, *((float *)buffer));
167 			break;
168 		case B_DOUBLE_TYPE:
169 			printf("%s : double : %f\n", fileName, *((double *)buffer));
170 			break;
171 		case B_BOOL_TYPE:
172 			printf("%s : bool : %d\n", fileName, *((unsigned char *)buffer));
173 			break;
174 		case B_STRING_TYPE:
175 		case B_MIME_STRING_TYPE:
176 			printf("%s : string : %s\n", fileName, buffer);
177 			break;
178 
179 		default:
180 			// The rest of the attributes types are displayed as raw data
181 			printf("%s : raw_data : \n", fileName);
182 			dumpRawData(buffer, size);
183 			break;
184 	}
185 
186 	free(buffer);
187 	return B_OK;
188 }
189 
190 
191 int
192 main(int argc, char *argv[])
193 {
194 	char *program = strrchr(argv[0], '/');
195 	if (program == NULL)
196 		program = argv[0];
197 	else
198 		program++;
199 
200 	if (argc > 2) {
201 		int32 attrNameIndex = 1;
202 		bool keepRaw = false;
203 
204 		// see if user wants to get to the raw data of the attribute
205 		if (strcmp(argv[attrNameIndex], "--raw") == 0 ||
206 			strcmp(argv[attrNameIndex], "-r") == 0) {
207 			attrNameIndex++;
208 			keepRaw = true;
209 		}
210 
211 		// Cat the attribute for every file given
212 		for (int32 i = attrNameIndex + 1; i < argc; i++) {
213 			status_t status = catAttr(argv[attrNameIndex], argv[i], keepRaw);
214 			if (status != B_OK) {
215 				fprintf(stderr, "%s: file \"%s\", attribute \"%s\": %s\n",
216 					program, argv[i], argv[attrNameIndex], strerror(status));
217 			}
218 		}
219 	} else {
220 		// Issue usage message
221 		fprintf(stderr, "usage: %s [--raw|-r] attr_name file1 [file2...]\n", program);
222 		// Be's original version -only- returned 1 if the
223 		// amount of parameters was wrong, not if the file
224 		// or attribute couldn't be found (!)
225 		// In all other cases it returned 0
226 		return 1;
227 	}
228 
229 	return 0;
230 }
231 
232 
233