xref: /haiku/src/bin/addattr/main.cpp (revision 44d19f4d32b8f7e9c01f00294c87ca5cc2e057f7)
1 /*
2  * Copyright 2010, Jérôme Duval.
3  * Copyright 2004-2015, 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 <getopt.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include <File.h>
16 #include <Mime.h>
17 #include <TypeConstants.h>
18 
19 #include "addAttr.h"
20 
21 
22 #define ERR(msg, args...)	fprintf(stderr, "%s: " msg, kProgramName, args)
23 #define ERR_0(msg)			fprintf(stderr, "%s: " msg, kProgramName)
24 
25 
26 static struct option const kLongOptions[] = {
27 	{"help", no_argument, 0, 'h'},
28 	{NULL}
29 };
30 
31 
32 #ifndef HAIKU_HOST_PLATFORM_SUNOS
33 extern const char *__progname;
34 #endif
35 #ifdef HAIKU_HOST_PLATFORM_SUNOS
36 static const char *kProgramName = "addattr";
37 #else
38 static const char *kProgramName = __progname;
39 #endif
40 
41 
42 // supported types (if you add any, make sure that writeAttr() handles
43 // them properly)
44 
45 const struct {
46 	type_code	type;
47 	const char	*name;
48 } kSupportedTypes[] = {
49 	{B_STRING_TYPE, "string"},
50 	{B_MIME_STRING_TYPE, "mime"},
51 
52 	{B_INT32_TYPE, "int32"},
53 	{B_INT32_TYPE, "int"},
54 	{B_UINT32_TYPE, "uint32"},
55 	{B_UINT32_TYPE, "uint"},
56 
57 	{B_INT64_TYPE, "int64"},
58 	{B_INT64_TYPE, "llong"},
59 	{B_UINT64_TYPE, "uint64"},
60 	{B_UINT64_TYPE, "ullong"},
61 
62 	{B_FLOAT_TYPE, "float"},
63 	{B_DOUBLE_TYPE, "double"},
64 
65 	{B_BOOL_TYPE, "bool"},
66 
67 	{B_TIME_TYPE, "time"},
68 
69 	{B_VECTOR_ICON_TYPE, "icon"},
70 	{B_RAW_TYPE, "raw"},
71 };
72 const uint32 kNumSupportedTypes = sizeof(kSupportedTypes)
73 	/ sizeof(kSupportedTypes[0]);
74 
75 
76 /*!	For the given string that the user specifies as attribute type
77 	in the command line, this function tries to figure out the
78 	corresponding Be API value.
79 
80 	On success, "result" will contain that value
81 	On failure, B_BAD_VALUE is returned and "result" is not modified
82 */
83 static status_t
84 typeForString(const char* string, type_code* _result)
85 {
86 	for (uint32 i = 0; i < kNumSupportedTypes; i++) {
87 		if (!strcmp(string, kSupportedTypes[i].name)) {
88 			*_result = kSupportedTypes[i].type;
89 			return B_OK;
90 		}
91 	}
92 
93 	// type didn't show up - in this case, we try to parse
94 	// the string as number and use it directly as type code
95 
96 	if (sscanf(string, "%" B_SCNi32, _result) == 1)
97 		return B_OK;
98 
99 	// if that didn't work, try the string as a char-type-code
100 	// enclosed in single quotes
101 	uchar type[4];
102 	if (sscanf(string, "'%c%c%c%c'", &type[0], &type[1], &type[2], &type[3]) == 4) {
103 		*_result = (type[0] << 24) | (type[1] << 16) | (type[2] << 8) | type[3];
104 		return B_OK;
105 	}
106 
107 	return B_BAD_VALUE;
108 }
109 
110 
111 void
112 usage(int returnValue)
113 {
114 	fprintf(stderr, "usage: %s [-t type|-c code] [ -P ] attr value file1 [file2...]\n"
115 		"   or: %s [-f value-from-file] [-t type|-c code] [ -P ] attr file1 [file2...]\n\n"
116 		"\t-P : Don't resolve links\n"
117 		"\tThe '-t' and '-c' options are alternatives; use one or the other.\n"
118 		"\ttype is one of:\n"
119 		"\t\tstring, mime, int, int32, uint32, llong, int64, uint64,\n"
120 		"\t\tfloat, double, bool, icon, time, raw\n"
121 		"\t\tor a numeric value (ie. 0x1234, 42, ...),\n"
122 		"\t\tor an escape-quoted type code, eg. \\'MICN\\'\n"
123 		"\tThe default is \"string\"\n"
124 		"\tcode is a four-char type ID (eg. MICN)\n", kProgramName, kProgramName);
125 
126 	exit(returnValue);
127 }
128 
129 
130 void
131 invalidAttrType(const char* attrTypeName)
132 {
133 	fprintf(stderr, "%s: attribute type \"%s\" is not valid\n", kProgramName,
134 		attrTypeName);
135 	fprintf(stderr, "\tTry one of: string, mime, int, llong, float, double,\n"
136 		"\t\tbool, icon, time, raw, or a numeric value (ie. 0x1234, 42, ...),\n"
137 		"\t\tor a quoted type code, eg.: \\'MICN\\'\n"
138 		"\t\tOr enter the actual type code with the '-c' option\n");
139 
140 	exit(1);
141 }
142 
143 
144 void
145 invalidTypeCode(const char* attrTypeName)
146 {
147 	fprintf(stderr, "%s: attribute type code \"%s\" is not valid\n", kProgramName,
148 		attrTypeName);
149 	fprintf(stderr, "\tIt must be exactly four characters\n");
150 
151 	exit(1);
152 }
153 
154 
155 void
156 invalidBoolValue(const char* value)
157 {
158 	fprintf(stderr, "%s: attribute value \"%s\" is not valid\n", kProgramName,
159 		value);
160 	fprintf(stderr, "\tBool accepts: 0, f, false, disabled, off,\n"
161 		"\t\t1, t, true, enabled, on\n");
162 
163 	exit(1);
164 }
165 
166 
167 int
168 main(int argc, char* argv[])
169 {
170 	type_code attrType = B_STRING_TYPE;
171 	char* attrValue = NULL;
172 	size_t valueFileLength = 0;
173 	bool resolveLinks = true;
174 
175 	int c;
176 	while ((c = getopt_long(argc, argv, "hf:t:c:P", kLongOptions, NULL)) != -1) {
177 		switch (c) {
178 			case 0:
179 				break;
180 			case 'f':
181 			{
182 				// retrieve attribute value from file
183 				BFile file;
184 				off_t size;
185 				status_t status = file.SetTo(optarg, B_READ_ONLY);
186 				if (status < B_OK) {
187 					ERR("can't read attribute value from file %s: %s\n",
188 						optarg, strerror(status));
189 					return 1;
190 				}
191 
192 				status = file.GetSize(&size);
193 				if (status == B_OK) {
194 					if (size == 0) {
195 						ERR_0("attribute value is empty: 0 bytes\n");
196 						return 1;
197 					}
198 					if (size > 4 * 1024 * 1024) {
199 						ERR("attribute value is too large: %" B_PRIdOFF
200 							" bytes\n", size);
201 						return 1;
202 					}
203 					attrValue = (char*)malloc(size);
204 					if (attrValue != NULL)
205 						status = file.Read(attrValue, size);
206 					else
207 						status = B_NO_MEMORY;
208 				}
209 
210 				if (status < B_OK) {
211 					ERR("can't read attribute value: %s\n", strerror(status));
212 					return 1;
213 				}
214 
215 				valueFileLength = (size_t)size;
216 				break;
217 			}
218 			case 't':
219 				// Get the attribute type
220 				if (typeForString(optarg, &attrType) != B_OK)
221 					invalidAttrType(optarg);
222 				break;
223 			case 'c':
224 				if (strlen(optarg) == 4) {
225 					// Get the type code directly
226 					char code[] = "'    '";
227 					strncpy(code + 1, optarg, 4);
228 					if (typeForString(code, &attrType) == B_OK)
229 						break;
230 				}
231 				invalidTypeCode(optarg);
232 			case 'P':
233 				resolveLinks = false;
234 				break;
235 			case 'h':
236 				usage(0);
237 				break;
238 			default:
239 				usage(1);
240 				break;
241 		}
242 	}
243 
244 	if (argc - optind < 1)
245 		usage(1);
246 	const char* attrName = argv[optind++];
247 
248 	if (argc - optind < 1)
249 		usage(1);
250 	if (!valueFileLength)
251 		attrValue = argv[optind++];
252 
253 	if (argc - optind < 1)
254 		usage(1);
255 
256 	// Now that we gathered all the information proceed
257 	// to add the attribute to the file(s)
258 
259 	int result = 0;
260 
261 	for (; optind < argc; optind++) {
262 		status_t status = addAttr(argv[optind], attrType, attrName, attrValue,
263 			valueFileLength, resolveLinks);
264 
265 		// special case for bool types
266 		if (status == B_BAD_VALUE && attrType == B_BOOL_TYPE)
267 			invalidBoolValue(attrValue);
268 
269 		if (status != B_OK) {
270 			ERR("can't add attribute to file %s: %s\n", argv[optind],
271 				strerror(status));
272 
273 			// proceed files, but return an error at the end
274 			result = 1;
275 		}
276 	}
277 
278 	if (valueFileLength)
279 		free(attrValue);
280 
281 	return result;
282 }
283 
284