1cbaec888SMichael Lotz/*
2cbaec888SMichael Lotz * Copyright 2009, Haiku Inc. All rights reserved.
3cbaec888SMichael Lotz * Distributed under the terms of the MIT License.
4cbaec888SMichael Lotz *
5cbaec888SMichael Lotz * Authors:
6cbaec888SMichael Lotz *		Michael Lotz <mmlr@mlotz.ch>
7cbaec888SMichael Lotz */
8cbaec888SMichael Lotz
9cbaec888SMichael Lotz#include <stdio.h>
10cbaec888SMichael Lotz#include <stdlib.h>
11c26b324eSMichael Lotz#include <string.h>
12cbaec888SMichael Lotz
13cbaec888SMichael Lotz#include <fs_attr.h>
14cbaec888SMichael Lotz
15cbaec888SMichael Lotz#include <Directory.h>
16cbaec888SMichael Lotz#include <Entry.h>
17cbaec888SMichael Lotz#include <File.h>
18cbaec888SMichael Lotz#include <Node.h>
19cbaec888SMichael Lotz
20cbaec888SMichael Lotz
21cbaec888SMichael Lotz#define ATTRIBUTE_FILE_MAGIC	'attr'
22cbaec888SMichael Lotz#define ATTRIBUTE_DIR_NAME		"_HAIKU"
23cbaec888SMichael Lotz#define COPY_BUFFER_SIZE		128 * 1024
24cbaec888SMichael Lotz
25cbaec888SMichael Lotz
26cbaec888SMichael Lotzstruct attribute_file {
27cbaec888SMichael Lotz	uint32		magic; // 'attr'
28cbaec888SMichael Lotz	uint32		entry_count;
29cbaec888SMichael Lotz	uint8		entries[1];
30cbaec888SMichael Lotz} _PACKED;
31cbaec888SMichael Lotz
32cbaec888SMichael Lotz
33cbaec888SMichael Lotzstruct attribute_entry {
34cbaec888SMichael Lotz	type_code	type;
35cbaec888SMichael Lotz	uint32		size;
36cbaec888SMichael Lotz	uint8		name_length; // including 0 byte
37cbaec888SMichael Lotz	char		name[1]; // 0 terminated, followed by data
38cbaec888SMichael Lotz} _PACKED;
39cbaec888SMichael Lotz
40cbaec888SMichael Lotz
41cbaec888SMichael Lotzvoid
42cbaec888SMichael Lotzrecurse_directory(BDirectory &directory, uint8 *copyBuffer)
43cbaec888SMichael Lotz{
44cbaec888SMichael Lotz	BNode node;
45cbaec888SMichael Lotz	entry_ref ref;
46cbaec888SMichael Lotz	BDirectory attributeDir;
47cbaec888SMichael Lotz	bool attributeDirCreated = false;
48cbaec888SMichael Lotz	char nameBuffer[B_FILE_NAME_LENGTH];
49cbaec888SMichael Lotz	directory.Rewind();
50cbaec888SMichael Lotz
51cbaec888SMichael Lotz	while (directory.GetNextRef(&ref) == B_OK) {
52cbaec888SMichael Lotz		if (strcmp(ref.name, ATTRIBUTE_DIR_NAME) == 0)
53cbaec888SMichael Lotz			continue;
54cbaec888SMichael Lotz
55cbaec888SMichael Lotz		if (node.SetTo(&ref) != B_OK) {
56cbaec888SMichael Lotz			printf("failed to set node to ref \"%s\"\n", ref.name);
57cbaec888SMichael Lotz			continue;
58cbaec888SMichael Lotz		}
59cbaec888SMichael Lotz
60cbaec888SMichael Lotz		node.RewindAttrs();
61cbaec888SMichael Lotz		BFile attributeFile;
62cbaec888SMichael Lotz		uint32 attributeCount = 0;
63cbaec888SMichael Lotz		while (node.GetNextAttrName(nameBuffer) == B_OK) {
64cbaec888SMichael Lotz			attr_info info;
65cbaec888SMichael Lotz			if (node.GetAttrInfo(nameBuffer, &info) != B_OK) {
66cbaec888SMichael Lotz				printf("failed to get attr info of \"%s\" on file \"%s\"\n",
67cbaec888SMichael Lotz					nameBuffer, ref.name);
68cbaec888SMichael Lotz				continue;
69cbaec888SMichael Lotz			}
70cbaec888SMichael Lotz
71cbaec888SMichael Lotz			if (attributeCount == 0) {
72cbaec888SMichael Lotz				if (!attributeDirCreated) {
73cbaec888SMichael Lotz					directory.CreateDirectory(ATTRIBUTE_DIR_NAME, NULL);
74cbaec888SMichael Lotz					if (!directory.Contains(ATTRIBUTE_DIR_NAME,
75cbaec888SMichael Lotz						B_DIRECTORY_NODE)) {
76cbaec888SMichael Lotz						printf("attribute store directory not available\n");
77cbaec888SMichael Lotz						return;
78cbaec888SMichael Lotz					}
79cbaec888SMichael Lotz
80cbaec888SMichael Lotz					attributeDir.SetTo(&directory, ATTRIBUTE_DIR_NAME);
81cbaec888SMichael Lotz					attributeDirCreated = true;
82cbaec888SMichael Lotz				}
83cbaec888SMichael Lotz
84cbaec888SMichael Lotz				attributeDir.CreateFile(ref.name, NULL);
85cbaec888SMichael Lotz				if (attributeFile.SetTo(&attributeDir, ref.name,
86cbaec888SMichael Lotz					B_WRITE_ONLY | B_ERASE_FILE) != B_OK) {
87cbaec888SMichael Lotz					printf("cannot open attribute file for writing\n");
88cbaec888SMichael Lotz					break;
89cbaec888SMichael Lotz				}
90cbaec888SMichael Lotz
91cbaec888SMichael Lotz				attributeFile.Seek(sizeof(attribute_file) - 1, SEEK_SET);
92cbaec888SMichael Lotz			}
93cbaec888SMichael Lotz
94cbaec888SMichael Lotz			attribute_entry entry;
95cbaec888SMichael Lotz			entry.type = info.type;
96cbaec888SMichael Lotz			entry.size = info.size;
97cbaec888SMichael Lotz			entry.name_length = strlen(nameBuffer) + 1;
98cbaec888SMichael Lotz			attributeFile.Write(&entry, sizeof(attribute_entry) - 1);
99cbaec888SMichael Lotz			attributeFile.Write(nameBuffer, entry.name_length);
100cbaec888SMichael Lotz
101cbaec888SMichael Lotz			off_t offset = 0;
102cbaec888SMichael Lotz			while (info.size > 0) {
103cbaec888SMichael Lotz				size_t copySize = min_c(info.size, COPY_BUFFER_SIZE);
104cbaec888SMichael Lotz				if (node.ReadAttr(nameBuffer, info.type, offset, copyBuffer,
105cbaec888SMichael Lotz					copySize) < B_OK) {
106cbaec888SMichael Lotz					printf("error reading attribute \"%s\" of file \"%s\"\n",
107cbaec888SMichael Lotz						nameBuffer, ref.name);
108cbaec888SMichael Lotz					return;
109cbaec888SMichael Lotz				}
110cbaec888SMichael Lotz
111cbaec888SMichael Lotz				attributeFile.Write(copyBuffer, copySize);
112cbaec888SMichael Lotz				info.size -= COPY_BUFFER_SIZE;
113cbaec888SMichael Lotz				offset += COPY_BUFFER_SIZE;
114cbaec888SMichael Lotz			}
115cbaec888SMichael Lotz
116cbaec888SMichael Lotz			attributeCount++;
117cbaec888SMichael Lotz		}
118cbaec888SMichael Lotz
119cbaec888SMichael Lotz		if (attributeCount > 0) {
120cbaec888SMichael Lotz			attribute_file file;
121cbaec888SMichael Lotz			file.magic = ATTRIBUTE_FILE_MAGIC;
122cbaec888SMichael Lotz			file.entry_count = attributeCount;
123cbaec888SMichael Lotz			attributeFile.WriteAt(0, &file, sizeof(attribute_file) - 1);
124cbaec888SMichael Lotz		}
125cbaec888SMichael Lotz
126cbaec888SMichael Lotz		if (node.IsDirectory()) {
127cbaec888SMichael Lotz			BDirectory subDirectory(&ref);
128cbaec888SMichael Lotz			recurse_directory(subDirectory, copyBuffer);
129cbaec888SMichael Lotz		}
130cbaec888SMichael Lotz	}
131cbaec888SMichael Lotz}
132cbaec888SMichael Lotz
133cbaec888SMichael Lotz
134cbaec888SMichael Lotzint
135cbaec888SMichael Lotzmain(int argc, char *argv[])
136cbaec888SMichael Lotz{
137cbaec888SMichael Lotz	if (argc < 2) {
138cbaec888SMichael Lotz		printf("usage: %s <root directory>\n", argv[0]);
139cbaec888SMichael Lotz		return 1;
140cbaec888SMichael Lotz	}
141cbaec888SMichael Lotz
142cbaec888SMichael Lotz	uint8 *copyBuffer = (uint8 *)malloc(COPY_BUFFER_SIZE);
143cbaec888SMichael Lotz	if (copyBuffer == NULL) {
144cbaec888SMichael Lotz		printf("cannot allocate copy buffer\n");
145cbaec888SMichael Lotz		return 2;
146cbaec888SMichael Lotz	}
147cbaec888SMichael Lotz
148cbaec888SMichael Lotz	BDirectory root(argv[1]);
149cbaec888SMichael Lotz	recurse_directory(root, copyBuffer);
150cbaec888SMichael Lotz
151cbaec888SMichael Lotz	free(copyBuffer);
152cbaec888SMichael Lotz	return 0;
153cbaec888SMichael Lotz}