Improved error messages (and how they are done).
No longer locks the file during attribute retrieval. No longer needs libbe.so. Added support for some additional types. Will no longer try to read in a 4GB attribute - at max, it will read 64 kB from an attribute. Also changed output style of the raw data type - please contact me if you desperately think we should revert that back (ie. in case the old output was actually of use for something). As the original author suggested, we're now using isgraph() to improve the character preview of the raw data. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10371 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+155
-198
@@ -1,221 +1,178 @@
|
||||
/*
|
||||
* Copyright 2004, Axel Dörfler, [email protected].
|
||||
* 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)
|
||||
|
||||
// [email protected]: note the original one doesn't link to libbe or libstdc++
|
||||
|
||||
#include <SupportDefs.h>
|
||||
#include <TypeConstants.h>
|
||||
#include <Mime.h>
|
||||
|
||||
#include <Entry.h>
|
||||
#include <Node.h>
|
||||
#include <kernel/fs_attr.h>
|
||||
#include <fs_attr.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user