1 /* 2 * Copyright 2010, Jérôme Duval. 3 * Copyright 2004-2007, 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_VECTOR_ICON_TYPE, "icon"}, 68 69 {B_RAW_TYPE, "raw"}, 70 }; 71 const uint32 kNumSupportedTypes = sizeof(kSupportedTypes) 72 / sizeof(kSupportedTypes[0]); 73 74 75 /*! For the given string that the user specifies as attribute type 76 in the command line, this function tries to figure out the 77 corresponding Be API value. 78 79 On success, "result" will contain that value 80 On failure, B_BAD_VALUE is returned and "result" is not modified 81 */ 82 static status_t 83 typeForString(const char *string, type_code *_result) 84 { 85 for (uint32 i = 0; i < kNumSupportedTypes; i++) { 86 if (!strcmp(string, kSupportedTypes[i].name)) { 87 *_result = kSupportedTypes[i].type; 88 return B_OK; 89 } 90 } 91 92 // type didn't show up - in this case, we parse the string 93 // as number and use it directly as type code 94 95 if (sscanf(string, "%" B_SCNu32, _result) == 1) 96 return B_OK; 97 98 uchar type[4]; 99 if (sscanf(string, "'%c%c%c%c'", &type[0], &type[1], &type[2], &type[3]) == 4) { 100 *_result = (type[0] << 24) | (type[1] << 16) | (type[2] << 8) | type[3]; 101 return B_OK; 102 } 103 104 return B_BAD_VALUE; 105 } 106 107 108 void 109 usage(int returnValue) 110 { 111 fprintf(stderr, "usage: %s [-t type] [ -P ] attr value file1 [file2...]\n" 112 " or: %s [-f value-from-file] [-t type] [ -P ] attr file1 [file2...]\n\n" 113 "\t-P : Don't resolve links\n" 114 "\tType is one of:\n" 115 "\t\tstring, mime, int, llong, float, double, bool, icon, raw\n" 116 "\t\tor a numeric value (ie. 0x1234, 42, 'ABCD', ...)\n" 117 "\tThe default is \"string\"\n", kProgramName, kProgramName); 118 119 exit(returnValue); 120 } 121 122 123 void 124 invalidAttrType(const char *attrTypeName) 125 { 126 fprintf(stderr, "%s: attribute type \"%s\" is not valid\n", kProgramName, 127 attrTypeName); 128 fprintf(stderr, "\tTry one of: string, mime, int, llong, float, double,\n"); 129 fprintf(stderr, "\t\tbool, icon, raw, or a numeric value (ie. 0x1234, 42, 'ABCD'" 130 ", ...)\n"); 131 132 exit(1); 133 } 134 135 136 void 137 invalidBoolValue(const char *value) 138 { 139 fprintf(stderr, "%s: attribute value \"%s\" is not valid\n", kProgramName, 140 value); 141 fprintf(stderr, "\tBool accepts: 0, f, false, disabled, off,\n"); 142 fprintf(stderr, "\t\t1, t, true, enabled, on\n"); 143 144 exit(1); 145 } 146 147 148 int 149 main(int argc, char *argv[]) 150 { 151 type_code attrType = B_STRING_TYPE; 152 char *attrValue = NULL; 153 size_t valueFileLength = 0; 154 bool resolveLinks = true; 155 156 int c; 157 while ((c = getopt_long(argc, argv, "hf:t:P", kLongOptions, NULL)) != -1) { 158 switch (c) { 159 case 0: 160 break; 161 case 'f': 162 { 163 // retrieve attribute value from file 164 BFile file; 165 off_t size; 166 status_t status = file.SetTo(optarg, B_READ_ONLY); 167 if (status < B_OK) { 168 ERR("can't read attribute value from file %s: %s\n", 169 optarg, strerror(status)); 170 return 1; 171 } 172 173 status = file.GetSize(&size); 174 if (status == B_OK) { 175 if (size == 0) { 176 ERR_0("attribute value is empty: 0 bytes\n"); 177 return 1; 178 } 179 if (size > 4 * 1024 * 1024) { 180 ERR("attribute value is too large: %" B_PRIdOFF 181 " bytes\n", size); 182 return 1; 183 } 184 attrValue = (char *)malloc(size); 185 if (attrValue != NULL) 186 status = file.Read(attrValue, size); 187 else 188 status = B_NO_MEMORY; 189 } 190 191 if (status < B_OK) { 192 ERR("can't read attribute value: %s\n", strerror(status)); 193 return 1; 194 } 195 196 valueFileLength = (size_t)size; 197 break; 198 } 199 case 't': 200 // Get the attribute type 201 if (typeForString(optarg, &attrType) != B_OK) 202 invalidAttrType(optarg); 203 break; 204 case 'P': 205 resolveLinks = false; 206 break; 207 case 'h': 208 usage(0); 209 break; 210 default: 211 usage(1); 212 break; 213 } 214 } 215 216 if (argc - optind < 1) 217 usage(1); 218 const char *attrName = argv[optind++]; 219 220 if (argc - optind < 1) 221 usage(1); 222 if (!valueFileLength) 223 attrValue = argv[optind++]; 224 225 if (argc - optind < 1) 226 usage(1); 227 228 // Now that we gathered all the information proceed 229 // to add the attribute to the file(s) 230 231 int result = 0; 232 233 for (; optind < argc; optind++) { 234 status_t status = addAttr(argv[optind], attrType, attrName, attrValue, 235 valueFileLength, resolveLinks); 236 237 // special case for bool types 238 if (status == B_BAD_VALUE && attrType == B_BOOL_TYPE) 239 invalidBoolValue(attrValue); 240 241 if (status != B_OK) { 242 ERR("can't add attribute to file %s: %s\n", argv[optind], 243 strerror(status)); 244 245 // proceed files, but return an error at the end 246 result = 1; 247 } 248 } 249 250 if (valueFileLength) 251 free(attrValue); 252 253 return result; 254 } 255 256