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
26static struct option const kLongOptions[] = {
27	{"help", no_argument, 0, 'h'},
28	{NULL}
29};
30
31
32#ifndef HAIKU_HOST_PLATFORM_SUNOS
33extern const char *__progname;
34#endif
35#ifdef HAIKU_HOST_PLATFORM_SUNOS
36static const char *kProgramName = "addattr";
37#else
38static const char *kProgramName = __progname;
39#endif
40
41
42// supported types (if you add any, make sure that writeAttr() handles
43// them properly)
44
45const 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};
71const 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*/
82static status_t
83typeForString(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
108void
109usage(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
123void
124invalidAttrType(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
136void
137invalidBoolValue(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
148int
149main(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