1/*
2 * Copyright (c) 2003-2005, Haiku
3 *
4 * This software is part of the Haiku distribution and is covered
5 * by the MIT license.
6 *
7 * Authors:
8 *		Scott Dellinger (dellinsd@myrealbox.com)
9 *		Axel D��rfler, axeld@pinc-software.de.
10 */
11
12/**	Description: Adds an index to a volume. */
13
14
15#include <fs_info.h>
16#include <fs_index.h>
17#include <TypeConstants.h>
18#include <Directory.h>
19#include <Path.h>
20#include <Volume.h>
21
22#include <getopt.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <errno.h>
27
28
29static struct option const kLongOptions[] = {
30	{"volume", required_argument, 0, 'd'},
31	{"type", required_argument, 0, 't'},
32	{"copy-from", required_argument, 0, 'f'},
33	{"verbose", no_argument, 0, 'v'},
34	{"help", no_argument, 0, 'h'},
35	{NULL}
36};
37
38extern const char *__progname;
39static const char *kProgramName = __progname;
40
41
42static void
43copy_indexes(dev_t from, dev_t to, bool verbose)
44{
45	DIR *indexes = fs_open_index_dir(from);
46
47	if (verbose)
48		puts("Copying indexes:");
49
50	while (dirent *dirent = fs_read_index_dir(indexes)) {
51		if (!strcmp(dirent->d_name, "name")
52			|| !strcmp(dirent->d_name, "size")
53			|| !strcmp(dirent->d_name, "last_modified"))
54			continue;
55
56		index_info info;
57		if (fs_stat_index(from, dirent->d_name, &info) != 0) {
58			fprintf(stderr, "%s: Skipped index \"%s\": %s\n",
59				kProgramName, dirent->d_name, strerror(errno));
60			continue;
61		}
62
63		if (fs_create_index(to, dirent->d_name, info.type, 0) != 0) {
64			if (errno == B_BAD_VALUE || errno == B_FILE_EXISTS) {
65				// B_BAD_VALUE is what BeOS returns here...
66				continue;
67			}
68			fprintf(stderr, "%s: Could not create index \"%s\": %s\n",
69				kProgramName, dirent->d_name, strerror(errno));
70		} else if (verbose)
71			printf("\t%s\n", dirent->d_name);
72	}
73
74	fs_close_index_dir(indexes);
75}
76
77
78static void
79usage(int status)
80{
81	fprintf(stderr,
82		"Usage: %s [options] <attribute>\n"
83		"Creates a new index for the specified attribute.\n"
84		"\n"
85		"  -d, --volume=PATH\ta path on the volume to which the index will be added,\n"
86		"\t\t\tdefaults to current volume.\n"
87		"  -t, --type=TYPE	the type of the attribute being indexed.  One of \"int\",\n"
88		"\t\t\t\"llong\", \"string\", \"float\", or \"double\".\n"
89		"\t\t\tDefaults to \"string\".\n"
90		"      --copy-from\tpath to volume to copy the indexes from.\n"
91		"  -v, --verbose\t\tprint information about the index being created\n",
92		kProgramName);
93
94	exit(status);
95}
96
97
98int
99main(int argc, char **argv)
100{
101	const char *indexTypeName = "string";
102	int indexType = B_STRING_TYPE;
103	char *indexName = NULL;
104	bool verbose = false;
105	dev_t device = -1, copyFromDevice = -1;
106
107	int c;
108	while ((c = getopt_long(argc, argv, "d:ht:v", kLongOptions, NULL)) != -1) {
109		switch (c) {
110			case 0:
111				break;
112			case 'd':
113				device = dev_for_path(optarg);
114				if (device < 0) {
115					fprintf(stderr, "%s: can't get information about volume: %s\n",
116						kProgramName, optarg);
117					return -1;
118				}
119				break;
120			case 'f':
121				copyFromDevice = dev_for_path(optarg);
122				if (copyFromDevice < 0) {
123					fprintf(stderr, "%s: can't get information about volume: %s\n",
124						kProgramName, optarg);
125					return -1;
126				}
127				break;
128			case 'h':
129				usage(0);
130				break;
131			case 't':
132				indexTypeName = optarg;
133				if (strncmp("int", optarg, 3) == 0)
134					indexType = B_INT32_TYPE;
135				else if (strncmp("llong", optarg, 5) == 0)
136					indexType = B_INT64_TYPE;
137				else if (strncmp("string", optarg, 6) == 0)
138					indexType = B_STRING_TYPE;
139				else if (strncmp("float", optarg, 5) == 0)
140					indexType = B_FLOAT_TYPE;
141				else if (strncmp("double", optarg, 6) == 0)
142					indexType = B_DOUBLE_TYPE;
143				else
144					usage(1);
145				break;
146			case 'v':
147				verbose = 1;
148				break;
149			default:
150				usage(1);
151				break;
152		}
153	}
154
155	if (device == -1) {
156		// Create the index on the volume of the current
157		// directory if no volume was specified.
158
159		device = dev_for_path(".");
160		if (device < 0) {
161			fprintf(stderr, "%s: can't get information about current volume\n", kProgramName);
162			return -1;
163		}
164	}
165
166	if (copyFromDevice != -1) {
167		copy_indexes(copyFromDevice, device, verbose);
168		return 0;
169	}
170
171	if (argc - optind == 1) {
172		// last argument
173		indexName = argv[optind];
174	} else
175		usage(1);
176
177	if (verbose) {
178		/* Get the mount point of the specified volume. */
179		BVolume volume(device);
180		BDirectory dir;
181		volume.GetRootDirectory(&dir);
182		BPath path(&dir, NULL);
183
184		printf("Creating index \"%s\" of type %s on volume mounted at %s.\n",
185			indexName, indexTypeName, path.Path());
186	}
187
188	if (fs_create_index(device, indexName, indexType, 0) != 0)
189		fprintf(stderr, "%s: Could not create index: %s\n", kProgramName, strerror(errno));
190
191	return 0;
192}
193