xref: /haiku/src/bin/addattr/main.cpp (revision e0ef64750f3169cd634bb2f7a001e22488b05231)
1 /*
2  * Copyright 2010, Jérôme Duval.
3  * Copyright 2004-2007, 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_VECTOR_ICON_TYPE, "icon"},
68 
69 	{B_RAW_TYPE, "raw"},
70 };
71 const uint32 kNumSupportedTypes = sizeof(kSupportedTypes)
72 	/ sizeof(kSupportedTypes[0]);
73 
74 
75 /*!	For the given string that the user specifies as attribute type
76 	in the command line, this function tries to figure out the
77 	corresponding Be API value.
78 
79 	On success, "result" will contain that value
80 	On failure, B_BAD_VALUE is returned and "result" is not modified
81 */
82 static status_t
83 typeForString(const char *string, type_code *_result)
84 {
85 	for (uint32 i = 0; i < kNumSupportedTypes; i++) {
86 		if (!strcmp(string, kSupportedTypes[i].name)) {
87 			*_result = kSupportedTypes[i].type;
88 			return B_OK;
89 		}
90 	}
91 
92 	// type didn't show up - in this case, we parse the string
93 	// as number and use it directly as type code
94 
95 	if (sscanf(string, "%" B_SCNu32, _result) == 1)
96 		return B_OK;
97 
98 	uchar type[4];
99 	if (sscanf(string, "'%c%c%c%c'", &type[0], &type[1], &type[2], &type[3]) == 4) {
100 		*_result = (type[0] << 24) | (type[1] << 16) | (type[2] << 8) | type[3];
101 		return B_OK;
102 	}
103 
104 	return B_BAD_VALUE;
105 }
106 
107 
108 void
109 usage(int returnValue)
110 {
111 	fprintf(stderr, "usage: %s [-t type] [ -P ] attr value file1 [file2...]\n"
112 		"   or: %s [-f value-from-file] [-t type] [ -P ] attr file1 [file2...]\n\n"
113 		"\t-P : Don't resolve links\n"
114 		"\tType is one of:\n"
115 		"\t\tstring, mime, int, llong, float, double, bool, icon, raw\n"
116 		"\t\tor a numeric value (ie. 0x1234, 42, 'ABCD', ...)\n"
117 		"\tThe default is \"string\"\n", kProgramName, kProgramName);
118 
119 	exit(returnValue);
120 }
121 
122 
123 void
124 invalidAttrType(const char *attrTypeName)
125 {
126 	fprintf(stderr, "%s: attribute type \"%s\" is not valid\n", kProgramName,
127 		attrTypeName);
128 	fprintf(stderr, "\tTry one of: string, mime, int, llong, float, double,\n");
129 	fprintf(stderr, "\t\tbool, icon, raw, or a numeric value (ie. 0x1234, 42, 'ABCD'"
130 		", ...)\n");
131 
132 	exit(1);
133 }
134 
135 
136 void
137 invalidBoolValue(const char *value)
138 {
139 	fprintf(stderr, "%s: attribute value \"%s\" is not valid\n", kProgramName,
140 		value);
141 	fprintf(stderr, "\tBool accepts: 0, f, false, disabled, off,\n");
142 	fprintf(stderr, "\t\t1, t, true, enabled, on\n");
143 
144 	exit(1);
145 }
146 
147 
148 int
149 main(int argc, char *argv[])
150 {
151 	type_code attrType = B_STRING_TYPE;
152 	char *attrValue = NULL;
153 	size_t valueFileLength = 0;
154 	bool resolveLinks = true;
155 
156 	int c;
157 	while ((c = getopt_long(argc, argv, "hf:t:P", kLongOptions, NULL)) != -1) {
158 		switch (c) {
159 			case 0:
160 				break;
161 			case 'f':
162 			{
163 				// retrieve attribute value from file
164 				BFile file;
165 				off_t size;
166 				status_t status = file.SetTo(optarg, B_READ_ONLY);
167 				if (status < B_OK) {
168 					ERR("can't read attribute value from file %s: %s\n",
169 						optarg, strerror(status));
170 					return 1;
171 				}
172 
173 				status = file.GetSize(&size);
174 				if (status == B_OK) {
175 					if (size == 0) {
176 						ERR_0("attribute value is empty: 0 bytes\n");
177 						return 1;
178 					}
179 					if (size > 4 * 1024 * 1024) {
180 						ERR("attribute value is too large: %" B_PRIdOFF
181 							" bytes\n", size);
182 						return 1;
183 					}
184 					attrValue = (char *)malloc(size);
185 					if (attrValue != NULL)
186 						status = file.Read(attrValue, size);
187 					else
188 						status = B_NO_MEMORY;
189 				}
190 
191 				if (status < B_OK) {
192 					ERR("can't read attribute value: %s\n", strerror(status));
193 					return 1;
194 				}
195 
196 				valueFileLength = (size_t)size;
197 				break;
198 			}
199 			case 't':
200 				// Get the attribute type
201 				if (typeForString(optarg, &attrType) != B_OK)
202 					invalidAttrType(optarg);
203 				break;
204 			case 'P':
205 				resolveLinks = false;
206 				break;
207 			case 'h':
208 				usage(0);
209 				break;
210 			default:
211 				usage(1);
212 				break;
213 		}
214 	}
215 
216 	if (argc - optind < 1)
217 		usage(1);
218 	const char *attrName = argv[optind++];
219 
220 	if (argc - optind < 1)
221 		usage(1);
222 	if (!valueFileLength)
223 		attrValue = argv[optind++];
224 
225 	if (argc - optind < 1)
226 		usage(1);
227 
228 	// Now that we gathered all the information proceed
229 	// to add the attribute to the file(s)
230 
231 	int result = 0;
232 
233 	for (; optind < argc; optind++) {
234 		status_t status = addAttr(argv[optind], attrType, attrName, attrValue,
235 			valueFileLength, resolveLinks);
236 
237 		// special case for bool types
238 		if (status == B_BAD_VALUE && attrType == B_BOOL_TYPE)
239 			invalidBoolValue(attrValue);
240 
241 		if (status != B_OK) {
242 			ERR("can't add attribute to file %s: %s\n", argv[optind],
243 				strerror(status));
244 
245 			// proceed files, but return an error at the end
246 			result = 1;
247 		}
248 	}
249 
250 	if (valueFileLength)
251 		free(attrValue);
252 
253 	return result;
254 }
255 
256