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