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 try to parse 94 // the string as number and use it directly as type code 95 96 if (sscanf(string, "%" B_SCNi32, _result) == 1) 97 return B_OK; 98 99 // if that didn't work, try the string as a char-type-code 100 // enclosed in single quotes 101 uchar type[4]; 102 if (sscanf(string, "'%c%c%c%c'", &type[0], &type[1], &type[2], &type[3]) == 4) { 103 *_result = (type[0] << 24) | (type[1] << 16) | (type[2] << 8) | type[3]; 104 return B_OK; 105 } 106 107 return B_BAD_VALUE; 108 } 109 110 111 void 112 usage(int returnValue) 113 { 114 fprintf(stderr, "usage: %s [-t type|-c code] [ -P ] attr value file1 [file2...]\n" 115 " or: %s [-f value-from-file] [-t type|-c code] [ -P ] attr file1 [file2...]\n\n" 116 "\t-P : Don't resolve links\n" 117 "\tThe '-t' and '-c' options are alternatives; use one or the other.\n" 118 "\ttype is one of:\n" 119 "\t\tstring, mime, int, int32, uint32, llong, int64, uint64,\n" 120 "\t\tfloat, double, bool, icon, time, raw\n" 121 "\t\tor a numeric value (ie. 0x1234, 42, ...),\n" 122 "\t\tor an escape-quoted type code, eg. \\'MICN\\'\n" 123 "\tThe default is \"string\"\n" 124 "\tcode is a four-char type ID (eg. MICN)\n", kProgramName, kProgramName); 125 126 exit(returnValue); 127 } 128 129 130 void 131 invalidAttrType(const char* attrTypeName) 132 { 133 fprintf(stderr, "%s: attribute type \"%s\" is not valid\n", kProgramName, 134 attrTypeName); 135 fprintf(stderr, "\tTry one of: string, mime, int, llong, float, double,\n" 136 "\t\tbool, icon, time, raw, or a numeric value (ie. 0x1234, 42, ...),\n" 137 "\t\tor a quoted type code, eg.: \\'MICN\\'\n" 138 "\t\tOr enter the actual type code with the '-c' option\n"); 139 140 exit(1); 141 } 142 143 144 void 145 invalidTypeCode(const char* attrTypeName) 146 { 147 fprintf(stderr, "%s: attribute type code \"%s\" is not valid\n", kProgramName, 148 attrTypeName); 149 fprintf(stderr, "\tIt must be exactly four characters\n"); 150 151 exit(1); 152 } 153 154 155 void 156 invalidBoolValue(const char* value) 157 { 158 fprintf(stderr, "%s: attribute value \"%s\" is not valid\n", kProgramName, 159 value); 160 fprintf(stderr, "\tBool accepts: 0, f, false, disabled, off,\n" 161 "\t\t1, t, true, enabled, on\n"); 162 163 exit(1); 164 } 165 166 167 int 168 main(int argc, char* argv[]) 169 { 170 type_code attrType = B_STRING_TYPE; 171 char* attrValue = NULL; 172 size_t valueFileLength = 0; 173 bool resolveLinks = true; 174 175 int c; 176 while ((c = getopt_long(argc, argv, "hf:t:c:P", kLongOptions, NULL)) != -1) { 177 switch (c) { 178 case 0: 179 break; 180 case 'f': 181 { 182 // retrieve attribute value from file 183 BFile file; 184 off_t size; 185 status_t status = file.SetTo(optarg, B_READ_ONLY); 186 if (status < B_OK) { 187 ERR("can't read attribute value from file %s: %s\n", 188 optarg, strerror(status)); 189 return 1; 190 } 191 192 status = file.GetSize(&size); 193 if (status == B_OK) { 194 if (size == 0) { 195 ERR_0("attribute value is empty: 0 bytes\n"); 196 return 1; 197 } 198 if (size > 4 * 1024 * 1024) { 199 ERR("attribute value is too large: %" B_PRIdOFF 200 " bytes\n", size); 201 return 1; 202 } 203 attrValue = (char*)malloc(size); 204 if (attrValue != NULL) 205 status = file.Read(attrValue, size); 206 else 207 status = B_NO_MEMORY; 208 } 209 210 if (status < B_OK) { 211 ERR("can't read attribute value: %s\n", strerror(status)); 212 return 1; 213 } 214 215 valueFileLength = (size_t)size; 216 break; 217 } 218 case 't': 219 // Get the attribute type 220 if (typeForString(optarg, &attrType) != B_OK) 221 invalidAttrType(optarg); 222 break; 223 case 'c': 224 if (strlen(optarg) == 4) { 225 // Get the type code directly 226 char code[] = "' '"; 227 strncpy(code + 1, optarg, 4); 228 if (typeForString(code, &attrType) == B_OK) 229 break; 230 } 231 invalidTypeCode(optarg); 232 case 'P': 233 resolveLinks = false; 234 break; 235 case 'h': 236 usage(0); 237 break; 238 default: 239 usage(1); 240 break; 241 } 242 } 243 244 if (argc - optind < 1) 245 usage(1); 246 const char* attrName = argv[optind++]; 247 248 if (argc - optind < 1) 249 usage(1); 250 if (!valueFileLength) 251 attrValue = argv[optind++]; 252 253 if (argc - optind < 1) 254 usage(1); 255 256 // Now that we gathered all the information proceed 257 // to add the attribute to the file(s) 258 259 int result = 0; 260 261 for (; optind < argc; optind++) { 262 status_t status = addAttr(argv[optind], attrType, attrName, attrValue, 263 valueFileLength, resolveLinks); 264 265 // special case for bool types 266 if (status == B_BAD_VALUE && attrType == B_BOOL_TYPE) 267 invalidBoolValue(attrValue); 268 269 if (status != B_OK) { 270 ERR("can't add attribute to file %s: %s\n", argv[optind], 271 strerror(status)); 272 273 // proceed files, but return an error at the end 274 result = 1; 275 } 276 } 277 278 if (valueFileLength) 279 free(attrValue); 280 281 return result; 282 } 283 284