xref: /haiku/src/bin/addattr/addAttr.cpp (revision 4bd0c1066b227cec4b79883bdef697c7a27f2e90)
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 
27 template<class Type>
28 ssize_t
29 writeAttrValue(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 */
45 static ssize_t
46 writeAttr(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 */
150 status_t
151 addAttr(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