1 /* 2 * Copyright 2004-2015, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2002, Ryan Fleet. 4 * 5 * Distributed under the terms of the MIT license. 6 */ 7 8 9 #include <String.h> 10 #include <TypeConstants.h> 11 #include <Mime.h> 12 13 #include <fs_attr.h> 14 15 #include <ctype.h> 16 #include <string.h> 17 #include <stdio.h> 18 19 20 /*! Dumps the contents of the attribute in the form of raw data. This view 21 is used for the type B_RAW_TYPE, for custom types and for any type that 22 is not directly supported by the utility "addattr". 23 */ 24 static void 25 dump_raw_data(const char *buffer, size_t size) 26 { 27 const uint32 kChunkSize = 16; 28 uint32 dumpPosition = 0; 29 30 while (dumpPosition < size) { 31 // Position for this line 32 printf("\t%04" B_PRIx32 ": ", dumpPosition); 33 34 // Print the bytes in form of hexadecimal numbers 35 for (uint32 i = 0; i < kChunkSize; i++) { 36 if (dumpPosition + i < size) { 37 printf("%02x ", (uint8)buffer[dumpPosition + i]); 38 } else 39 printf(" "); 40 } 41 42 // Print the bytes in form of printable characters 43 // (whenever possible) 44 printf(" "); 45 for (uint32 i = 0; i < kChunkSize; i++) { 46 if (dumpPosition < size) { 47 char c = buffer[dumpPosition]; 48 putchar(isgraph(c) ? c : '.'); 49 } else 50 putchar(' '); 51 52 dumpPosition++; 53 } 54 printf("\n"); 55 } 56 } 57 58 59 static void 60 show_attr_contents(BNode& node, const char* attribute, const attr_info& info) 61 { 62 // limit size of the attribute, only the first kLimit byte will make it on 63 // screen 64 int kLimit = 256; 65 bool cut = false; 66 off_t size = info.size; 67 if (size > kLimit) { 68 size = kLimit; 69 cut = true; 70 } 71 72 char buffer[kLimit]; 73 ssize_t bytesRead = node.ReadAttr(attribute, info.type, 0, buffer, size); 74 if (bytesRead != size) { 75 fprintf(stderr, "Could only read %" B_PRIdOFF " bytes from attribute!\n", 76 size); 77 return; 78 } 79 80 switch (info.type) { 81 case B_INT8_TYPE: 82 printf("%" B_PRId8 "\n", *((int8 *)buffer)); 83 break; 84 case B_UINT8_TYPE: 85 printf("%" B_PRIu8 "\n", *((uint8 *)buffer)); 86 break; 87 case B_INT16_TYPE: 88 printf("%" B_PRId16 "\n", *((int16 *)buffer)); 89 break; 90 case B_UINT16_TYPE: 91 printf("%" B_PRIu16 "\n", *((uint16 *)buffer)); 92 break; 93 case B_INT32_TYPE: 94 printf("%" B_PRId32 "\n", *((int32 *)buffer)); 95 break; 96 case B_UINT32_TYPE: 97 printf("%" B_PRIu32 "\n", *((uint32 *)buffer)); 98 break; 99 case B_INT64_TYPE: 100 printf("%" B_PRId64 "\n", *((int64 *)buffer)); 101 break; 102 case B_UINT64_TYPE: 103 printf("%" B_PRIu64 "\n", *((uint64 *)buffer)); 104 break; 105 case B_FLOAT_TYPE: 106 printf("%f\n", *((float *)buffer)); 107 break; 108 case B_DOUBLE_TYPE: 109 printf("%f\n", *((double *)buffer)); 110 break; 111 case B_BOOL_TYPE: 112 printf("%d\n", *((unsigned char *)buffer)); 113 break; 114 case B_TIME_TYPE: 115 { 116 char stringBuffer[256]; 117 struct tm timeInfo; 118 localtime_r((time_t *)buffer, &timeInfo); 119 strftime(stringBuffer, sizeof(stringBuffer), "%c", &timeInfo); 120 printf("%s\n", stringBuffer); 121 break; 122 } 123 case B_STRING_TYPE: 124 case B_MIME_STRING_TYPE: 125 case 'MSIG': 126 case 'MSDC': 127 case 'MPTH': 128 printf("%s\n", buffer); 129 break; 130 131 case B_MESSAGE_TYPE: 132 { 133 BMessage message; 134 if (!cut && message.Unflatten(buffer) == B_OK) { 135 putchar('\n'); 136 message.PrintToStream(); 137 putchar('\n'); 138 break; 139 } 140 // supposed to fall through 141 } 142 143 default: 144 // The rest of the attributes types are displayed as raw data 145 putchar('\n'); 146 dump_raw_data(buffer, size); 147 putchar('\n'); 148 break; 149 } 150 } 151 152 153 static const char * 154 get_type(type_code type) 155 { 156 static char buffer[32]; 157 158 switch (type) { 159 case B_MIME_STRING_TYPE: 160 return "MIME String"; 161 case B_RAW_TYPE: 162 return "Raw Data"; 163 164 case B_STRING_TYPE: 165 return "Text"; 166 case B_INT64_TYPE: 167 return "Int-64"; 168 case B_UINT64_TYPE: 169 return "Uint-64"; 170 case B_INT32_TYPE: 171 return "Int-32"; 172 case B_UINT32_TYPE: 173 return "Uint-32"; 174 case B_INT16_TYPE: 175 return "Int-16"; 176 case B_UINT16_TYPE: 177 return "Uint-16"; 178 case B_INT8_TYPE: 179 return "Int-8"; 180 case B_UINT8_TYPE: 181 return "Uint-8"; 182 case B_BOOL_TYPE: 183 return "Boolean"; 184 case B_FLOAT_TYPE: 185 return "Float"; 186 case B_DOUBLE_TYPE: 187 return "Double"; 188 189 case B_MINI_ICON_TYPE: 190 return "Mini Icon"; 191 case B_LARGE_ICON_TYPE: 192 return "Icon"; 193 194 default: 195 { 196 int32 missed = 0, shift = 24; 197 uint8 value[4]; 198 for (int32 i = 0; i < 4; i++, shift -= 8) { 199 value[i] = uint8(type >> shift); 200 if (value[i] < ' ' || value[i] > 127) { 201 value[i] = '.'; 202 missed++; 203 } 204 } 205 206 if (missed < 2) { 207 sprintf(buffer, "'%c%c%c%c'", value[0], value[1], value[2], 208 value[3]); 209 } else 210 sprintf(buffer, "0x%08" B_PRIx32, type); 211 212 return buffer; 213 } 214 } 215 } 216 217 218 int 219 main(int argc, char *argv[]) 220 { 221 const char *program = strrchr(argv[0], '/'); 222 if (program == NULL) 223 program = argv[0]; 224 else 225 program++; 226 227 bool printContents = false; 228 229 if (argc > 2 && (!strcmp(argv[1], "--long") || !strcmp(argv[1], "-l"))) { 230 printContents = true; 231 argc--; 232 argv++; 233 } 234 235 if (argc < 2 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) { 236 printf("usage: %s [-l|--long] 'filename' ['filename' ...]\n" 237 " -l, --long Shows the attribute contents as well.\n", program); 238 return argc == 2 ? 0 : 1; 239 } 240 241 off_t total = 0; 242 243 for (int i = 1; i < argc; ++i) { 244 BNode node(argv[i]); 245 246 status_t status = node.InitCheck(); 247 if (status < B_OK) { 248 fprintf(stderr, "%s: initialization failed for \"%s\": %s\n", 249 program, argv[i], strerror(status)); 250 return 0; 251 } 252 253 printf("File: %s\n", argv[i]); 254 255 const int kTypeWidth = 12; 256 const int kSizeWidth = 10; 257 const int kNameWidth = 36; 258 const int kContentsWidth = 21; 259 printf("%*s %*s %-*s%s\n", kTypeWidth, "Type", kSizeWidth, "Size", 260 kNameWidth, "Name", printContents ? "Contents" : ""); 261 262 BString separator; 263 separator.SetTo('-', kTypeWidth + kSizeWidth + kNameWidth 264 + (printContents ? kContentsWidth : 0)); 265 puts(separator.String()); 266 267 char name[B_ATTR_NAME_LENGTH]; 268 while (node.GetNextAttrName(name) == B_OK) { 269 attr_info attrInfo; 270 271 status = node.GetAttrInfo(name, &attrInfo); 272 if (status >= B_OK) { 273 printf("%*s", kTypeWidth, get_type(attrInfo.type)); 274 printf("% *" B_PRId64 " ", kSizeWidth, attrInfo.size); 275 printf("\"%s\"", name); 276 277 if (printContents) { 278 // padding 279 int length = kNameWidth - 2 - strlen(name); 280 if (length > 0) 281 printf("%*s", length, ""); 282 283 show_attr_contents(node, name, attrInfo); 284 } else 285 putchar('\n'); 286 287 total += attrInfo.size; 288 } else { 289 fprintf(stderr, "%s: stat failed for \"%s\": %s\n", 290 program, name, strerror(status)); 291 } 292 } 293 } 294 295 printf("\n%" B_PRId64 " bytes total in attributes.\n", total); 296 return 0; 297 } 298