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