diff --git a/src/apps/bin/catattr.cpp b/src/apps/bin/catattr.cpp index bcd7ce06b6..5fc32a4b6c 100644 --- a/src/apps/bin/catattr.cpp +++ b/src/apps/bin/catattr.cpp @@ -1,221 +1,178 @@ +/* + * Copyright 2004, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002, Sebastian Nozzi. + * + * Distributed under the terms of the MIT license. + */ -// Author: Sebastian Nozzi -// Created: 1st may 2002 -// Modifications: -// (please include author, date, and description) - -// mmu_man@sf.net: note the original one doesn't link to libbe or libstdc++ - -#include #include #include -#include -#include -#include +#include #include -#include +#include #include +#include -void catAttr( const char *attrName, const char *fileName ); -void dumpRawData( const char *buffer, off_t size ); -void putCharOrDot( uchar c ); -// Used to hold argv[0] along the program -char *completeToolName; +/** Used to present the characters in the raw data view */ -int main( int argc, char *argv[] ) +static void +putCharOrDot(uchar c) { - int returnCode; - - completeToolName = argv[0]; - returnCode = 0; - - if( argc > 2 ) { - - int i; - + putchar(isgraph(c) ? c : '.'); +} + + +/** Dumps the contents of the attribute in the form of + * raw data. This view is used for the type B_RAW_DATA_TYPE, + * for custom types and for any type that is not directly + * supported by the utility "addattr" + */ + +static void +dumpRawData(const char *buffer, size_t size) +{ + const uint32 kChunkSize = 16; + uint32 dumpPosition = 0; + + while (dumpPosition < size) { + // Position for this line + printf("0x%06lx: ", dumpPosition); + + // Print the bytes in form of hexadecimal numbers + for (uint32 i = 0; i < kChunkSize; i++) { + if (dumpPosition + i < size) { + printf("%02x ", (uint8)buffer[dumpPosition + i]); + } else + printf(" "); + } + + // Print the bytes in form of printable characters + // (whenever possible) + printf(" '"); + for (uint32 i = 0; i < kChunkSize; i++) { + if (dumpPosition < size) + putCharOrDot(buffer[dumpPosition]); + else + putchar(' '); + + dumpPosition++; + } + printf("'\n"); + } +} + + +static status_t +catAttr(const char *attribute, const char *fileName) +{ + int fd = open(fileName, O_RDONLY); + if (fd < 0) + return errno; + + attr_info info; + if (fs_stat_attr(fd, attribute, &info) < 0) + return errno; + + // limit size of the attribute, only the first 64k will make it on screen + off_t size = info.size; + if (size > 64 * 1024) + size = 64 * 1024; + + char buffer[size]; + ssize_t bytesRead = fs_read_attr(fd, attribute, info.type, 0, buffer, size); + if (bytesRead < 0) + return errno; + + if (bytesRead != size) { + fprintf(stderr, "Could only read %ld bytes from attribute!\n", bytesRead); + return B_ERROR; + } + + switch (info.type) { + case B_INT8_TYPE: + printf("%s : int8 : %d\n", fileName, *((int8 *)buffer)); + break; + case B_UINT8_TYPE: + printf("%s : uint8 : %u\n", fileName, *((uint8 *)buffer)); + break; + case B_INT16_TYPE: + printf("%s : int16 : %d\n", fileName, *((int16 *)buffer)); + break; + case B_UINT16_TYPE: + printf("%s : uint16 : %u\n", fileName, *((uint16 *)buffer)); + break; + case B_INT32_TYPE: + printf("%s : int32 : %ld\n", fileName, *((int32 *)buffer)); + break; + case B_UINT32_TYPE: + printf("%s : uint32 : %lu\n", fileName, *((uint32 *)buffer)); + break; + case B_INT64_TYPE: + printf("%s : int64 : %Ld\n", fileName, *((int64 *)buffer)); + break; + case B_UINT64_TYPE: + printf("%s : uint64 : %Lu\n", fileName, *((uint64 *)buffer)); + break; + case B_FLOAT_TYPE: + printf("%s : float : %f\n", fileName, *((float *)buffer)); + break; + case B_DOUBLE_TYPE: + printf("%s : double : %f\n", fileName, *((double *)buffer)); + break; + case B_BOOL_TYPE: + printf("%s : bool : %d\n", fileName, *((unsigned char *)buffer)); + break; + case B_STRING_TYPE: + case B_MIME_STRING_TYPE: + printf("%s : string : %s\n", fileName, buffer); + break; + + default: + // The rest of the attributes types are displayed as raw data + printf("%s : raw_data : \n", fileName); + dumpRawData(buffer, size); + break; + } + + return B_OK; +} + + +int +main(int argc, char *argv[]) +{ + char *program = strrchr(argv[0], '/'); + if (program == NULL) + program = argv[0]; + else + program++; + + if (argc > 2) { + const char *attr = argv[1]; + // Cat the attribute for every file given - for( i = 2; i < argc; i++ ) - catAttr( argv[1], argv[i] ); - + for (int32 i = 2; i < argc; i++) { + status_t status = catAttr(attr, argv[i]); + if (status != B_OK) { + fprintf(stderr, "%s: file \"%s\", attribute \"%s\": %s\n", + program, argv[i], attr, strerror(status)); + } + } } else { // Issue usage message - fprintf( stderr, "usage: %s attr_name file1 [file2...]\n", completeToolName ); + fprintf(stderr, "usage: %s attr_name file1 [file2...]\n", program); // Be's original version -only- returned 1 if the // amount of parameters was wrong, not if the file // or attribute couldn't be found (!) // In all other cases it returned 0 - returnCode = 1; + return 1; } - - return returnCode; + + return 0; } -void catAttr( const char *attrName, const char *fileName ) { - - BNode node; - // Traverse links - BEntry entry(fileName, true); - - node.SetTo(&entry); - // Release file descriptor, which are limited - entry.Unset(); - - if( node.InitCheck() == B_OK ){ - // I chose to lock the node just in case - // If you feel this is too protective remove it - if( node.Lock() == B_OK ) { - - attr_info attrInfo; - - if( node.GetAttrInfo( attrName, &attrInfo ) == B_OK ) { - char *rawBuffer; - - rawBuffer = (char*) malloc( attrInfo.size ); - - if( rawBuffer != NULL ) { - node.ReadAttr( attrName, attrInfo.type, 0, - rawBuffer, attrInfo.size ); - switch( attrInfo.type ) { - case B_INT32_TYPE: - printf("%s : int32 : %ld\n", fileName, *((int32*)rawBuffer) ); - break; - case B_INT64_TYPE: - printf("%s : int64 : %lld\n", fileName, *((int64*)rawBuffer) ); - break; - case B_FLOAT_TYPE: - printf("%s : float : %f\n", fileName, *((float*)rawBuffer) ); - break; - case B_DOUBLE_TYPE: - printf("%s : double : %f\n", fileName, *((double*)rawBuffer) ); - break; - case B_BOOL_TYPE: - printf("%s : bool : %d\n", fileName, *((unsigned char*)rawBuffer) ); - break; - case B_STRING_TYPE: - case B_MIME_STRING_TYPE: - printf("%s : string : %s\n", fileName, rawBuffer ); - break; - default: -#ifdef DEBUG -// This is to see the four letters that build up the attribute type -// in case you are ever unsure of what's going on -// After you got it, go and compare it against the types in -// TypeDefinitions.h - if(1){ - char x[4]; - memcpy( (void*)&x[0], (void*) &attrInfo.type, 4 ); - printf("%c%c%c%c\n",x[3],x[2],x[1],x[0]); - } -#endif - // The rest of the attributes types are displayed as raw data - // Surprisingly for me, even types like B_UINT32_TYPE or - // B_CHAR_TYPE... As of now I will implement this tool exactly - // as Be's original behaved, then we can see to change this - printf("%s : raw_data : \n", fileName ); - dumpRawData( rawBuffer, attrInfo.size ); - break; - } /* type-switch */ - free(rawBuffer); - } else { - // This message I thought myself. It doesn't correspond to Be's - // original version - fprintf( stderr, "Not enough memory to complete this operation\n" ); - } - } else { - // Although misleading, this is the message provided by Be's original - // version if the attribute could not be found - fprintf( stderr, "%s: file %s attribute %s: " - "No such file or directory\n", completeToolName, fileName, attrName ); - } - node.Unlock(); - } else { - // This message I also thought myself. It doesn't correspond to Be's - // original version - fprintf( stderr, "%s: unable lock file %s\n", completeToolName, fileName ); - } - } else { - fprintf( stderr, "%s: can\'t open file %s to cat attribute %s\n", - completeToolName, fileName, attrName ); - } -} - -// Dumps the contents of the attribute in the form of -// raw data. This view is used for the type B_RAW_DATA_TYPE, -// for custom types and for any type that is not directly -// supported by the utility "addattr" -void dumpRawData( const char *buffer, off_t size ) { - - off_t chunkEnd; - off_t dumpPosition; - off_t textPosition; - uchar c; - - chunkEnd = 0x10; - dumpPosition= 0; - - while( dumpPosition < size ) { - // Position for this line - printf( "0x%06lx: ", (unsigned long)dumpPosition ); - - textPosition = dumpPosition; - - // Print the bytes in form of hexadecimal numbers - while( dumpPosition < chunkEnd ) { - if( dumpPosition < size ){ - c = buffer[dumpPosition]; - printf( "%02x", c ); - if( dumpPosition+1 < size ) - putchar(','); - else - putchar(' '); - } else { - printf(" "); - } - dumpPosition++; - } - - // Print the bytes in form of printable characters - // (whenever possible) - printf(" \'"); - while( textPosition < chunkEnd ) { - if( textPosition < size ){ - c = buffer[textPosition]; - putCharOrDot( c ); - } else { - putchar(' '); - } - textPosition++; - } - printf("\'\n"); - - chunkEnd += 0x10; - }/* loop */ -} - -// Used to present the characters in the raw data view -void putCharOrDot( uchar c ) { -// By using this: - -// if( ! isgraph(c) ) - -// better results were archieved, the output was leaner -// but it's not the way it wokrs in Be's version. So I -// decided to let the "bug" there and maybe we can -// see what we do about it for R2 - - // Put the dot for non-printable characters - // (including and below space, which code is 32) - if( c <= ' ' ) - putchar('.'); - else - putchar(c); -} - - - -