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 extern const char *__progname; 33 static const char *kProgramName = __progname; 34 35 36 // supported types (if you add any, make sure that writeAttr() handles 37 // them properly) 38 39 const struct { 40 type_code type; 41 const char *name; 42 } kSupportedTypes[] = { 43 {B_STRING_TYPE, "string"}, 44 {B_MIME_STRING_TYPE, "mime"}, 45 46 {B_INT32_TYPE, "int32"}, 47 {B_INT32_TYPE, "int"}, 48 {B_UINT32_TYPE, "uint32"}, 49 {B_UINT32_TYPE, "uint"}, 50 51 {B_INT64_TYPE, "int64"}, 52 {B_INT64_TYPE, "llong"}, 53 {B_UINT64_TYPE, "uint64"}, 54 {B_UINT64_TYPE, "ullong"}, 55 56 {B_FLOAT_TYPE, "float"}, 57 {B_DOUBLE_TYPE, "double"}, 58 59 {B_BOOL_TYPE, "bool"}, 60 61 {B_TIME_TYPE, "time"}, 62 63 {B_VECTOR_ICON_TYPE, "icon"}, 64 {B_RAW_TYPE, "raw"}, 65 }; 66 const uint32 kNumSupportedTypes = sizeof(kSupportedTypes) 67 / sizeof(kSupportedTypes[0]); 68 69 70 /*! For the given string that the user specifies as attribute type 71 in the command line, this function tries to figure out the 72 corresponding Be API value. 73 74 On success, "result" will contain that value 75 On failure, B_BAD_VALUE is returned and "result" is not modified 76 */ 77 static status_t 78 typeForString(const char* string, type_code* _result) 79 { 80 for (uint32 i = 0; i < kNumSupportedTypes; i++) { 81 if (!strcmp(string, kSupportedTypes[i].name)) { 82 *_result = kSupportedTypes[i].type; 83 return B_OK; 84 } 85 } 86 87 // type didn't show up - in this case, we try to parse 88 // the string as number and use it directly as type code 89 90 if (sscanf(string, "%" B_SCNi32, _result) == 1) 91 return B_OK; 92 93 // if that didn't work, try the string as a char-type-code 94 // enclosed in single quotes 95 uchar type[4]; 96 if (sscanf(string, "'%c%c%c%c'", &type[0], &type[1], &type[2], &type[3]) == 4) { 97 *_result = (type[0] << 24) | (type[1] << 16) | (type[2] << 8) | type[3]; 98 return B_OK; 99 } 100 101 return B_BAD_VALUE; 102 } 103 104 105 void 106 usage(int returnValue) 107 { 108 fprintf(stderr, "usage: %s [-t type|-c code] [ -P ] attr value file1 [file2...]\n" 109 " or: %s [-f value-from-file] [-t type|-c code] [ -P ] attr file1 [file2...]\n\n" 110 "\t-P : Don't resolve links\n" 111 "\tThe '-t' and '-c' options are alternatives; use one or the other.\n" 112 "\ttype is one of:\n" 113 "\t\tstring, mime, int, int32, uint32, llong, int64, uint64,\n" 114 "\t\tfloat, double, bool, icon, time, raw\n" 115 "\t\tor a numeric value (ie. 0x1234, 42, ...),\n" 116 "\t\tor an escape-quoted type code, eg. \\'MICN\\'\n" 117 "\tThe default is \"string\"\n" 118 "\tcode is a four-char type ID (eg. MICN)\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 "\t\tbool, icon, time, raw, or a numeric value (ie. 0x1234, 42, ...),\n" 131 "\t\tor a quoted type code, eg.: \\'MICN\\'\n" 132 "\t\tOr enter the actual type code with the '-c' option\n"); 133 134 exit(1); 135 } 136 137 138 void 139 invalidTypeCode(const char* attrTypeName) 140 { 141 fprintf(stderr, "%s: attribute type code \"%s\" is not valid\n", kProgramName, 142 attrTypeName); 143 fprintf(stderr, "\tIt must be exactly four characters\n"); 144 145 exit(1); 146 } 147 148 149 void 150 invalidBoolValue(const char* value) 151 { 152 fprintf(stderr, "%s: attribute value \"%s\" is not valid\n", kProgramName, 153 value); 154 fprintf(stderr, "\tBool accepts: 0, f, false, disabled, off,\n" 155 "\t\t1, t, true, enabled, on\n"); 156 157 exit(1); 158 } 159 160 161 int 162 main(int argc, char* argv[]) 163 { 164 type_code attrType = B_STRING_TYPE; 165 char* attrValue = NULL; 166 size_t valueFileLength = 0; 167 bool resolveLinks = true; 168 169 int c; 170 while ((c = getopt_long(argc, argv, "hf:t:c:P", kLongOptions, NULL)) != -1) { 171 switch (c) { 172 case 0: 173 break; 174 case 'f': 175 { 176 // retrieve attribute value from file 177 BFile file; 178 off_t size; 179 status_t status = file.SetTo(optarg, B_READ_ONLY); 180 if (status < B_OK) { 181 ERR("can't read attribute value from file %s: %s\n", 182 optarg, strerror(status)); 183 return 1; 184 } 185 186 status = file.GetSize(&size); 187 if (status == B_OK) { 188 if (size == 0) { 189 ERR_0("attribute value is empty: 0 bytes\n"); 190 return 1; 191 } 192 if (size > 4 * 1024 * 1024) { 193 ERR("attribute value is too large: %" B_PRIdOFF 194 " bytes\n", size); 195 return 1; 196 } 197 attrValue = (char*)malloc(size); 198 if (attrValue != NULL) 199 status = file.Read(attrValue, size); 200 else 201 status = B_NO_MEMORY; 202 } 203 204 if (status < B_OK) { 205 ERR("can't read attribute value: %s\n", strerror(status)); 206 return 1; 207 } 208 209 valueFileLength = (size_t)size; 210 break; 211 } 212 case 't': 213 // Get the attribute type 214 if (typeForString(optarg, &attrType) != B_OK) 215 invalidAttrType(optarg); 216 break; 217 case 'c': 218 if (strlen(optarg) == 4) { 219 // Get the type code directly 220 char code[] = "' '"; 221 strncpy(code + 1, optarg, 4); 222 if (typeForString(code, &attrType) == B_OK) 223 break; 224 } 225 invalidTypeCode(optarg); 226 case 'P': 227 resolveLinks = false; 228 break; 229 case 'h': 230 usage(0); 231 break; 232 default: 233 usage(1); 234 break; 235 } 236 } 237 238 if (argc - optind < 1) 239 usage(1); 240 const char* attrName = argv[optind++]; 241 242 if (argc - optind < 1) 243 usage(1); 244 if (!valueFileLength) 245 attrValue = argv[optind++]; 246 247 if (argc - optind < 1) 248 usage(1); 249 250 // Now that we gathered all the information proceed 251 // to add the attribute to the file(s) 252 253 int result = 0; 254 255 for (; optind < argc; optind++) { 256 status_t status = addAttr(argv[optind], attrType, attrName, attrValue, 257 valueFileLength, resolveLinks); 258 259 // special case for bool types 260 if (status == B_BAD_VALUE && attrType == B_BOOL_TYPE) 261 invalidBoolValue(attrValue); 262 263 if (status != B_OK) { 264 ERR("can't add attribute to file %s: %s\n", argv[optind], 265 strerror(status)); 266 267 // proceed files, but return an error at the end 268 result = 1; 269 } 270 } 271 272 if (valueFileLength) 273 free(attrValue); 274 275 return result; 276 } 277 278