mirror of
https://review.haiku-os.org/haiku
synced 2025-02-08 14:49:58 +01:00
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@11909 a95241bf-73f2-0310-859d-f6bbb57e9c96
233 lines
5.6 KiB
C++
233 lines
5.6 KiB
C++
/*
|
|
* Copyright 2005, Stephan Aßmus, superstippi@yellowbites.com.
|
|
* Copyright 2004, Axel Dörfler, axeld@pinc-software.de.
|
|
* Copyright 2002, Sebastian Nozzi.
|
|
*
|
|
* Distributed under the terms of the MIT license.
|
|
*/
|
|
|
|
|
|
#include <Mime.h>
|
|
#include <TypeConstants.h>
|
|
|
|
#include <fs_attr.h>
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <malloc.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
|
|
/** Used to present the characters in the raw data view */
|
|
|
|
static void
|
|
putCharOrDot(uchar c)
|
|
{
|
|
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, bool keepRaw = false)
|
|
{
|
|
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 = (char*)malloc(size);
|
|
if (!buffer) {
|
|
fprintf(stderr, "Could not allocate read buffer!\n");
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
ssize_t bytesRead = fs_read_attr(fd, attribute, info.type, 0, buffer, size);
|
|
if (bytesRead < 0) {
|
|
free(buffer);
|
|
return errno;
|
|
}
|
|
|
|
if (bytesRead != size) {
|
|
fprintf(stderr, "Could only read %ld bytes from attribute!\n", bytesRead);
|
|
free(buffer);
|
|
return B_ERROR;
|
|
}
|
|
|
|
if (keepRaw) {
|
|
off_t pos = 0;
|
|
ssize_t written = 0;
|
|
while (pos < info.size) {
|
|
// write what we have read so far
|
|
written = write(STDOUT_FILENO, buffer, bytesRead);
|
|
// check for write error
|
|
if (written < bytesRead) {
|
|
if (written >= 0) {
|
|
fprintf(stderr, "Could only write %ld bytes to stream!\n", written);
|
|
written = B_ERROR;
|
|
} else
|
|
fprintf(stderr, "Failed to write to stream: %s\n", strerror(written));
|
|
break;
|
|
}
|
|
// read next chunk of data at pos
|
|
pos += bytesRead;
|
|
bytesRead = fs_read_attr(fd, attribute, info.type, pos, buffer, size);
|
|
// check for read error
|
|
if (bytesRead < size && pos + bytesRead < info.size) {
|
|
if (bytesRead >= 0)
|
|
fprintf(stderr, "Could only read %ld bytes from attribute!\n", bytesRead);
|
|
else
|
|
fprintf(stderr, "Failed to read from attribute: %s\n", strerror(bytesRead));
|
|
written = B_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
free(buffer);
|
|
if (written > 0)
|
|
written = B_OK;
|
|
return written;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
free(buffer);
|
|
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) {
|
|
int32 attrNameIndex = 1;
|
|
bool keepRaw = false;
|
|
|
|
// see if user wants to get to the raw data of the attribute
|
|
if (strcmp(argv[attrNameIndex], "--raw") == 0 ||
|
|
strcmp(argv[attrNameIndex], "-r") == 0) {
|
|
attrNameIndex++;
|
|
keepRaw = true;
|
|
}
|
|
|
|
// Cat the attribute for every file given
|
|
for (int32 i = attrNameIndex + 1; i < argc; i++) {
|
|
status_t status = catAttr(argv[attrNameIndex], argv[i], keepRaw);
|
|
if (status != B_OK) {
|
|
fprintf(stderr, "%s: file \"%s\", attribute \"%s\": %s\n",
|
|
program, argv[i], argv[attrNameIndex], strerror(status));
|
|
}
|
|
}
|
|
} else {
|
|
// Issue usage message
|
|
fprintf(stderr, "usage: %s [--raw|-r] 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
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|