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