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