1/*
2 * Copyright 2004-2015, Axel D��rfler, axeld@pinc-software.de.
3 * Copyright 2002, Sebastian Nozzi.
4 *
5 * Distributed under the terms of the MIT license.
6 */
7
8
9#include "addAttr.h"
10
11#include <TypeConstants.h>
12#include <Mime.h>
13
14#include <fs_attr.h>
15#ifdef __HAIKU__
16#	include <parsedate.h>
17#endif
18
19#include <ctype.h>
20#include <errno.h>
21#include <stdlib.h>
22#include <string.h>
23#include <strings.h>
24#include <unistd.h>
25
26
27template<class Type>
28ssize_t
29writeAttrValue(int fd, const char* name, type_code type, Type value)
30{
31	ssize_t bytes = fs_write_attr(fd, name, type, 0, &value, sizeof(Type));
32	if (bytes < 0)
33		return errno;
34
35	return bytes;
36}
37
38
39/*!	Writes an attribute to a node, taking the type into account and
40	converting the value accordingly
41
42	On success it will return the amount of bytes written
43	On failure it returns an error code (negative number)
44*/
45static ssize_t
46writeAttr(int fd, type_code type, const char* name, const char* value, size_t length)
47{
48	uint64 uint64value = 0;
49	int64 int64value = 0;
50	double floatValue = 0.0;
51
52	// parse number input at once
53
54	switch (type) {
55		case B_BOOL_TYPE:
56		case B_INT8_TYPE:
57		case B_INT16_TYPE:
58		case B_INT32_TYPE:
59		case B_INT64_TYPE:
60			int64value = strtoll(value, NULL, 0);
61			break;
62
63		case B_UINT8_TYPE:
64		case B_UINT16_TYPE:
65		case B_UINT32_TYPE:
66		case B_UINT64_TYPE:
67			uint64value = strtoull(value, NULL, 0);
68			break;
69
70		case B_FLOAT_TYPE:
71		case B_DOUBLE_TYPE:
72			floatValue = strtod(value, NULL);
73			break;
74	}
75
76	switch (type) {
77		case B_INT8_TYPE:
78			return writeAttrValue<int8>(fd, name, type, (int8)int64value);
79		case B_INT16_TYPE:
80			return writeAttrValue<int16>(fd, name, type, (int16)int64value);
81		case B_INT32_TYPE:
82			return writeAttrValue<int32>(fd, name, type, (int32)int64value);
83		case B_INT64_TYPE:
84			return writeAttrValue<int64>(fd, name, type, int64value);
85
86		case B_UINT8_TYPE:
87			return writeAttrValue<uint8>(fd, name, type, (uint8)uint64value);
88		case B_UINT16_TYPE:
89			return writeAttrValue<uint16>(fd, name, type, (uint16)uint64value);
90		case B_UINT32_TYPE:
91			return writeAttrValue<uint32>(fd, name, type, (uint32)uint64value);
92		case B_UINT64_TYPE:
93			return writeAttrValue<uint64>(fd, name, type, uint64value);
94
95		case B_FLOAT_TYPE:
96			return writeAttrValue<float>(fd, name, type, (float)floatValue);
97		case B_DOUBLE_TYPE:
98			return writeAttrValue<double>(fd, name, type, (double)floatValue);
99
100		case B_BOOL_TYPE:
101		{
102			uint8 boolValue = 0;
103
104			if (!strcasecmp(value, "true") || !strcasecmp(value, "t")
105				|| !strcasecmp(value, "on") || !strcasecmp(value, "enabled")
106				|| (isdigit(value[0]) && int64value == 1))
107				boolValue = 1;
108			else if (!strcasecmp(value, "false") || !strcasecmp(value, "f")
109				|| !strcasecmp(value, "off") || !strcasecmp(value, "disabled")
110				|| (isdigit(value[0]) && int64value == 0))
111				boolValue = 0;
112			else
113				return B_BAD_VALUE;
114
115			return writeAttrValue<uint8>(fd, name, B_BOOL_TYPE, boolValue);
116		}
117
118#ifdef __HAIKU__
119		case B_TIME_TYPE:
120		{
121			time_t timeValue = parsedate(value, time(NULL));
122			if (timeValue < 0)
123				return B_BAD_VALUE;
124
125			return writeAttrValue<time_t>(fd, name, B_TIME_TYPE, timeValue);
126		}
127#endif
128
129		case B_STRING_TYPE:
130		case B_MIME_STRING_TYPE:
131		default:
132			// For string, mime-strings and any other type we just write the value
133			// Note that the trailing NULL is added. If a length was given, we write
134			// the value directly, though.
135			ssize_t bytes = fs_write_attr(fd, name, type, 0, value,
136				length ? length : strlen(value) + 1);
137			if (bytes < 0)
138				return errno;
139
140			return bytes;
141	}
142}
143
144
145/*!	Adds an attribute to a file for the given type, name and value
146	Converts the value accordingly in case of numeric or boolean types
147
148	On success, it returns B_OK, or else an appropriate error code.
149*/
150status_t
151addAttr(const char* file, type_code type, const char* name,
152	const char* value, size_t length, bool resolveLinks)
153{
154	int fd = open(file, O_RDONLY | (resolveLinks ? 0 : O_NOTRAVERSE));
155	if (fd < 0)
156		return errno;
157
158	fs_remove_attr(fd, name);
159	ssize_t bytes = writeAttr(fd, type, name, value, length);
160
161	close(fd);
162
163	return bytes >= 0 ? B_OK : bytes;
164}
165
166