1 /* 2 * Copyright 2005, Stephan Aßmus, superstippi@yellowbites.com. 3 * Copyright 2004-2009, 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 <Mime.h> 11 #include <TypeConstants.h> 12 13 #include <fs_attr.h> 14 15 #include <ctype.h> 16 #include <errno.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <unistd.h> 21 22 23 /*! Used to present the characters in the raw data view */ 24 static void 25 putCharOrDot(uchar c) 26 { 27 putchar(isgraph(c) ? c : '.'); 28 } 29 30 31 /*! Dumps the contents of the attribute in the form of 32 raw data. This view is used for the type B_RAW_DATA_TYPE, 33 for custom types and for any type that is not directly 34 supported by the utility "addattr" 35 */ 36 static void 37 dumpRawData(const char *buffer, size_t size) 38 { 39 const uint32 kChunkSize = 16; 40 uint32 dumpPosition = 0; 41 42 while (dumpPosition < size) { 43 // Position for this line 44 printf("0x%06lx: ", dumpPosition); 45 46 // Print the bytes in form of hexadecimal numbers 47 for (uint32 i = 0; i < kChunkSize; i++) { 48 if (dumpPosition + i < size) { 49 printf("%02x ", (uint8)buffer[dumpPosition + i]); 50 } else 51 printf(" "); 52 } 53 54 // Print the bytes in form of printable characters 55 // (whenever possible) 56 printf(" '"); 57 for (uint32 i = 0; i < kChunkSize; i++) { 58 if (dumpPosition < size) 59 putCharOrDot(buffer[dumpPosition]); 60 else 61 putchar(' '); 62 63 dumpPosition++; 64 } 65 printf("'\n"); 66 } 67 } 68 69 70 static const char* 71 type_to_string(uint32 type) 72 { 73 if (type == B_RAW_TYPE) 74 return "raw_data"; 75 76 static char buffer[32]; 77 78 int32 missed = 0, shift = 24; 79 uint8 value[4]; 80 for (int32 i = 0; i < 4; i++, shift -= 8) { 81 value[i] = uint8(type >> shift); 82 if (value[i] < ' ' || value[i] > 127) { 83 value[i] = '.'; 84 missed++; 85 } 86 } 87 88 if (missed < 2) { 89 sprintf(buffer, "'%c%c%c%c'", value[0], value[1], value[2], 90 value[3]); 91 } else 92 sprintf(buffer, "0x%08lx", type); 93 94 return buffer; 95 } 96 97 98 static status_t 99 catAttr(const char *attribute, const char *fileName, bool keepRaw = false) 100 { 101 int fd = open(fileName, O_RDONLY); 102 if (fd < 0) 103 return errno; 104 105 attr_info info; 106 if (fs_stat_attr(fd, attribute, &info) < 0) 107 return errno; 108 109 // limit size of the attribute, only the first 64k will make it on screen 110 off_t size = info.size; 111 bool cut = false; 112 if (size > 64 * 1024) { 113 size = 64 * 1024; 114 cut = true; 115 } 116 117 char* buffer = (char*)malloc(size); 118 if (!buffer) { 119 fprintf(stderr, "Could not allocate read buffer!\n"); 120 return B_NO_MEMORY; 121 } 122 123 ssize_t bytesRead = fs_read_attr(fd, attribute, info.type, 0, buffer, size); 124 if (bytesRead < 0) { 125 free(buffer); 126 return errno; 127 } 128 129 if (bytesRead != size) { 130 fprintf(stderr, "Could only read %ld bytes from attribute!\n", 131 bytesRead); 132 free(buffer); 133 return B_ERROR; 134 } 135 136 if (keepRaw) { 137 off_t pos = 0; 138 ssize_t written = 0; 139 while (pos < info.size) { 140 // write what we have read so far 141 written = write(STDOUT_FILENO, buffer, bytesRead); 142 // check for write error 143 if (written < bytesRead) { 144 if (written >= 0) { 145 fprintf(stderr, "Could only write %ld bytes to stream!\n", 146 written); 147 written = B_ERROR; 148 } else { 149 fprintf(stderr, "Failed to write to stream: %s\n", 150 strerror(written)); 151 } 152 break; 153 } 154 // read next chunk of data at pos 155 pos += bytesRead; 156 bytesRead = fs_read_attr(fd, attribute, info.type, pos, buffer, 157 size); 158 // check for read error 159 if (bytesRead < size && pos + bytesRead < info.size) { 160 if (bytesRead >= 0) { 161 fprintf(stderr, "Could only read %ld bytes from " 162 "attribute!\n", bytesRead); 163 } else { 164 fprintf(stderr, "Failed to read from attribute: %s\n", 165 strerror(bytesRead)); 166 } 167 written = B_ERROR; 168 break; 169 } 170 } 171 free(buffer); 172 if (written > 0) 173 written = B_OK; 174 return written; 175 } 176 177 switch (info.type) { 178 case B_INT8_TYPE: 179 printf("%s : int8 : %d\n", fileName, *((int8 *)buffer)); 180 break; 181 case B_UINT8_TYPE: 182 printf("%s : uint8 : %u\n", fileName, *((uint8 *)buffer)); 183 break; 184 case B_INT16_TYPE: 185 printf("%s : int16 : %d\n", fileName, *((int16 *)buffer)); 186 break; 187 case B_UINT16_TYPE: 188 printf("%s : uint16 : %u\n", fileName, *((uint16 *)buffer)); 189 break; 190 case B_INT32_TYPE: 191 printf("%s : int32 : %ld\n", fileName, *((int32 *)buffer)); 192 break; 193 case B_UINT32_TYPE: 194 printf("%s : uint32 : %lu\n", fileName, *((uint32 *)buffer)); 195 break; 196 case B_INT64_TYPE: 197 printf("%s : int64 : %Ld\n", fileName, *((int64 *)buffer)); 198 break; 199 case B_UINT64_TYPE: 200 printf("%s : uint64 : %Lu\n", fileName, *((uint64 *)buffer)); 201 break; 202 case B_FLOAT_TYPE: 203 printf("%s : float : %f\n", fileName, *((float *)buffer)); 204 break; 205 case B_DOUBLE_TYPE: 206 printf("%s : double : %f\n", fileName, *((double *)buffer)); 207 break; 208 case B_BOOL_TYPE: 209 printf("%s : bool : %d\n", fileName, *((unsigned char *)buffer)); 210 break; 211 case B_STRING_TYPE: 212 printf("%s : string : %s\n", fileName, buffer); 213 break; 214 215 case B_MIME_STRING_TYPE: 216 case 'MSIG': 217 case 'MSDC': 218 case 'MPTH': 219 printf("%s : %s : %s\n", fileName, type_to_string(info.type), 220 buffer); 221 break; 222 223 case B_MESSAGE_TYPE: 224 { 225 BMessage message; 226 if (!cut && message.Unflatten(buffer) == B_OK) { 227 printf("%s : message :\n", fileName); 228 message.PrintToStream(); 229 break; 230 } 231 // supposed to fall through 232 } 233 234 default: 235 // The rest of the attributes types are displayed as raw data 236 printf("%s : %s : \n", fileName, type_to_string(info.type)); 237 dumpRawData(buffer, size); 238 break; 239 } 240 241 free(buffer); 242 return B_OK; 243 } 244 245 246 int 247 main(int argc, char *argv[]) 248 { 249 char *program = strrchr(argv[0], '/'); 250 if (program == NULL) 251 program = argv[0]; 252 else 253 program++; 254 255 if (argc > 2) { 256 int32 attrNameIndex = 1; 257 bool keepRaw = false; 258 259 // see if user wants to get to the raw data of the attribute 260 if (strcmp(argv[attrNameIndex], "--raw") == 0 || 261 strcmp(argv[attrNameIndex], "-r") == 0) { 262 attrNameIndex++; 263 keepRaw = true; 264 } 265 266 // Cat the attribute for every file given 267 for (int32 i = attrNameIndex + 1; i < argc; i++) { 268 status_t status = catAttr(argv[attrNameIndex], argv[i], keepRaw); 269 if (status != B_OK) { 270 fprintf(stderr, "%s: file \"%s\", attribute \"%s\": %s\n", 271 program, argv[i], argv[attrNameIndex], strerror(status)); 272 } 273 } 274 } else { 275 // Issue usage message 276 fprintf(stderr, "usage: %s [--raw|-r] <attribute-name> <file1> " 277 "[<file2>...]\n", program); 278 // Be's original version -only- returned 1 if the 279 // amount of parameters was wrong, not if the file 280 // or attribute couldn't be found (!) 281 // In all other cases it returned 0 282 return 1; 283 } 284 285 return 0; 286 } 287