1 /* 2 * Copyright 2004-2020, 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 buffer[min_c(bytesRead, kLimit - 1)] = '\0'; 80 81 switch (info.type) { 82 case B_INT8_TYPE: 83 printf("%" B_PRId8 "\n", *((int8 *)buffer)); 84 break; 85 case B_UINT8_TYPE: 86 printf("%" B_PRIu8 "\n", *((uint8 *)buffer)); 87 break; 88 case B_INT16_TYPE: 89 printf("%" B_PRId16 "\n", *((int16 *)buffer)); 90 break; 91 case B_UINT16_TYPE: 92 printf("%" B_PRIu16 "\n", *((uint16 *)buffer)); 93 break; 94 case B_INT32_TYPE: 95 printf("%" B_PRId32 "\n", *((int32 *)buffer)); 96 break; 97 case B_UINT32_TYPE: 98 printf("%" B_PRIu32 "\n", *((uint32 *)buffer)); 99 break; 100 case B_INT64_TYPE: 101 printf("%" B_PRId64 "\n", *((int64 *)buffer)); 102 break; 103 case B_UINT64_TYPE: 104 printf("%" B_PRIu64 "\n", *((uint64 *)buffer)); 105 break; 106 case B_FLOAT_TYPE: 107 printf("%f\n", *((float *)buffer)); 108 break; 109 case B_DOUBLE_TYPE: 110 printf("%f\n", *((double *)buffer)); 111 break; 112 case B_BOOL_TYPE: 113 printf("%d\n", *((unsigned char *)buffer)); 114 break; 115 case B_TIME_TYPE: 116 { 117 char stringBuffer[256]; 118 struct tm timeInfo; 119 localtime_r((time_t *)buffer, &timeInfo); 120 strftime(stringBuffer, sizeof(stringBuffer), "%c", &timeInfo); 121 printf("%s\n", stringBuffer); 122 break; 123 } 124 case B_STRING_TYPE: 125 case B_MIME_STRING_TYPE: 126 case 'MSIG': 127 case 'MSDC': 128 case 'MPTH': 129 printf("%s\n", buffer); 130 break; 131 132 case B_MESSAGE_TYPE: 133 { 134 BMessage message; 135 if (!cut && message.Unflatten(buffer) == B_OK) { 136 putchar('\n'); 137 message.PrintToStream(); 138 putchar('\n'); 139 break; 140 } 141 // supposed to fall through 142 } 143 144 default: 145 // The rest of the attributes types are displayed as raw data 146 putchar('\n'); 147 dump_raw_data(buffer, size); 148 putchar('\n'); 149 break; 150 } 151 } 152 153 154 static const char * 155 get_type(type_code type) 156 { 157 static char buffer[32]; 158 159 switch (type) { 160 case B_MIME_STRING_TYPE: 161 return "MIME String"; 162 case B_RAW_TYPE: 163 return "Raw Data"; 164 165 case B_STRING_TYPE: 166 return "Text"; 167 case B_INT64_TYPE: 168 return "Int-64"; 169 case B_UINT64_TYPE: 170 return "Uint-64"; 171 case B_INT32_TYPE: 172 return "Int-32"; 173 case B_UINT32_TYPE: 174 return "Uint-32"; 175 case B_INT16_TYPE: 176 return "Int-16"; 177 case B_UINT16_TYPE: 178 return "Uint-16"; 179 case B_INT8_TYPE: 180 return "Int-8"; 181 case B_UINT8_TYPE: 182 return "Uint-8"; 183 case B_BOOL_TYPE: 184 return "Boolean"; 185 case B_FLOAT_TYPE: 186 return "Float"; 187 case B_DOUBLE_TYPE: 188 return "Double"; 189 190 case B_MINI_ICON_TYPE: 191 return "Mini Icon"; 192 case B_LARGE_ICON_TYPE: 193 return "Icon"; 194 195 default: 196 { 197 int32 missed = 0, shift = 24; 198 uint8 value[4]; 199 for (int32 i = 0; i < 4; i++, shift -= 8) { 200 value[i] = uint8(type >> shift); 201 if (value[i] < ' ' || value[i] > 127) { 202 value[i] = '.'; 203 missed++; 204 } 205 } 206 207 if (missed < 2) { 208 sprintf(buffer, "'%c%c%c%c'", value[0], value[1], value[2], 209 value[3]); 210 } else 211 sprintf(buffer, "0x%08" B_PRIx32, type); 212 213 return buffer; 214 } 215 } 216 } 217 218 219 int 220 main(int argc, char *argv[]) 221 { 222 const char *program = strrchr(argv[0], '/'); 223 if (program == NULL) 224 program = argv[0]; 225 else 226 program++; 227 228 bool printContents = false; 229 230 if (argc > 2 && (!strcmp(argv[1], "--long") || !strcmp(argv[1], "-l"))) { 231 printContents = true; 232 argc--; 233 argv++; 234 } 235 236 if (argc < 2 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) { 237 printf("usage: %s [-l|--long] 'filename' ['filename' ...]\n" 238 " -l, --long Shows the attribute contents as well.\n", program); 239 return argc == 2 ? 0 : 1; 240 } 241 242 off_t total = 0; 243 244 for (int i = 1; i < argc; ++i) { 245 BNode node(argv[i]); 246 247 status_t status = node.InitCheck(); 248 if (status < B_OK) { 249 fprintf(stderr, "%s: initialization failed for \"%s\": %s\n", 250 program, argv[i], strerror(status)); 251 return 0; 252 } 253 254 printf("File: %s\n", argv[i]); 255 256 const int kTypeWidth = 12; 257 const int kSizeWidth = 10; 258 const int kNameWidth = 36; 259 const int kContentsWidth = 21; 260 printf("%*s %*s %-*s%s\n", kTypeWidth, "Type", kSizeWidth, "Size", 261 kNameWidth, "Name", printContents ? "Contents" : ""); 262 263 BString separator; 264 separator.SetTo('-', kTypeWidth + kSizeWidth + kNameWidth 265 + (printContents ? kContentsWidth : 0)); 266 puts(separator.String()); 267 268 char name[B_ATTR_NAME_LENGTH]; 269 while (node.GetNextAttrName(name) == B_OK) { 270 attr_info attrInfo; 271 272 status = node.GetAttrInfo(name, &attrInfo); 273 if (status >= B_OK) { 274 printf("%*s", kTypeWidth, get_type(attrInfo.type)); 275 printf("% *" B_PRId64 " ", kSizeWidth, attrInfo.size); 276 printf("\"%s\"", name); 277 278 if (printContents) { 279 // padding 280 int length = kNameWidth - 2 - strlen(name); 281 if (length > 0) 282 printf("%*s", length, ""); 283 284 show_attr_contents(node, name, attrInfo); 285 } else 286 putchar('\n'); 287 288 total += attrInfo.size; 289 } else { 290 fprintf(stderr, "%s: stat failed for \"%s\": %s\n", 291 program, name, strerror(status)); 292 } 293 } 294 } 295 296 printf("\n%" B_PRId64 " bytes total in attributes.\n", total); 297 return 0; 298 } 299