c26b324e20
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30853 a95241bf-73f2-0310-859d-f6bbb57e9c96
154 lines
3.4 KiB
C++
154 lines
3.4 KiB
C++
/*
|
|
* Copyright 2009, Haiku Inc. All rights reserved.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Authors:
|
|
* Michael Lotz <mmlr@mlotz.ch>
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <fs_attr.h>
|
|
|
|
#include <Directory.h>
|
|
#include <Entry.h>
|
|
#include <File.h>
|
|
#include <Node.h>
|
|
|
|
|
|
#define ATTRIBUTE_FILE_MAGIC 'attr'
|
|
#define ATTRIBUTE_DIR_NAME "_HAIKU"
|
|
#define COPY_BUFFER_SIZE 128 * 1024
|
|
|
|
|
|
struct attribute_file {
|
|
uint32 magic; // 'attr'
|
|
uint32 entry_count;
|
|
uint8 entries[1];
|
|
} _PACKED;
|
|
|
|
|
|
struct attribute_entry {
|
|
type_code type;
|
|
uint32 size;
|
|
uint8 name_length; // including 0 byte
|
|
char name[1]; // 0 terminated, followed by data
|
|
} _PACKED;
|
|
|
|
|
|
void
|
|
recurse_directory(BDirectory &directory, uint8 *copyBuffer)
|
|
{
|
|
BNode node;
|
|
entry_ref ref;
|
|
BDirectory attributeDir;
|
|
bool attributeDirCreated = false;
|
|
char nameBuffer[B_FILE_NAME_LENGTH];
|
|
directory.Rewind();
|
|
|
|
while (directory.GetNextRef(&ref) == B_OK) {
|
|
if (strcmp(ref.name, ATTRIBUTE_DIR_NAME) == 0)
|
|
continue;
|
|
|
|
if (node.SetTo(&ref) != B_OK) {
|
|
printf("failed to set node to ref \"%s\"\n", ref.name);
|
|
continue;
|
|
}
|
|
|
|
node.RewindAttrs();
|
|
BFile attributeFile;
|
|
uint32 attributeCount = 0;
|
|
while (node.GetNextAttrName(nameBuffer) == B_OK) {
|
|
attr_info info;
|
|
if (node.GetAttrInfo(nameBuffer, &info) != B_OK) {
|
|
printf("failed to get attr info of \"%s\" on file \"%s\"\n",
|
|
nameBuffer, ref.name);
|
|
continue;
|
|
}
|
|
|
|
if (attributeCount == 0) {
|
|
if (!attributeDirCreated) {
|
|
directory.CreateDirectory(ATTRIBUTE_DIR_NAME, NULL);
|
|
if (!directory.Contains(ATTRIBUTE_DIR_NAME,
|
|
B_DIRECTORY_NODE)) {
|
|
printf("attribute store directory not available\n");
|
|
return;
|
|
}
|
|
|
|
attributeDir.SetTo(&directory, ATTRIBUTE_DIR_NAME);
|
|
attributeDirCreated = true;
|
|
}
|
|
|
|
attributeDir.CreateFile(ref.name, NULL);
|
|
if (attributeFile.SetTo(&attributeDir, ref.name,
|
|
B_WRITE_ONLY | B_ERASE_FILE) != B_OK) {
|
|
printf("cannot open attribute file for writing\n");
|
|
break;
|
|
}
|
|
|
|
attributeFile.Seek(sizeof(attribute_file) - 1, SEEK_SET);
|
|
}
|
|
|
|
attribute_entry entry;
|
|
entry.type = info.type;
|
|
entry.size = info.size;
|
|
entry.name_length = strlen(nameBuffer) + 1;
|
|
attributeFile.Write(&entry, sizeof(attribute_entry) - 1);
|
|
attributeFile.Write(nameBuffer, entry.name_length);
|
|
|
|
off_t offset = 0;
|
|
while (info.size > 0) {
|
|
size_t copySize = min_c(info.size, COPY_BUFFER_SIZE);
|
|
if (node.ReadAttr(nameBuffer, info.type, offset, copyBuffer,
|
|
copySize) < B_OK) {
|
|
printf("error reading attribute \"%s\" of file \"%s\"\n",
|
|
nameBuffer, ref.name);
|
|
return;
|
|
}
|
|
|
|
attributeFile.Write(copyBuffer, copySize);
|
|
info.size -= COPY_BUFFER_SIZE;
|
|
offset += COPY_BUFFER_SIZE;
|
|
}
|
|
|
|
attributeCount++;
|
|
}
|
|
|
|
if (attributeCount > 0) {
|
|
attribute_file file;
|
|
file.magic = ATTRIBUTE_FILE_MAGIC;
|
|
file.entry_count = attributeCount;
|
|
attributeFile.WriteAt(0, &file, sizeof(attribute_file) - 1);
|
|
}
|
|
|
|
if (node.IsDirectory()) {
|
|
BDirectory subDirectory(&ref);
|
|
recurse_directory(subDirectory, copyBuffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
if (argc < 2) {
|
|
printf("usage: %s <root directory>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
uint8 *copyBuffer = (uint8 *)malloc(COPY_BUFFER_SIZE);
|
|
if (copyBuffer == NULL) {
|
|
printf("cannot allocate copy buffer\n");
|
|
return 2;
|
|
}
|
|
|
|
BDirectory root(argv[1]);
|
|
recurse_directory(root, copyBuffer);
|
|
|
|
free(copyBuffer);
|
|
return 0;
|
|
}
|