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