btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / bin / reindex.cpp
blob319e605fa300bbd1df4d6951687fb352aebab444
1 /*
2 * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
3 * This file may be used under the terms of the MIT License.
4 */
7 #include <ctype.h>
8 #include <errno.h>
9 #include <new>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
14 #include <Directory.h>
15 #include <Entry.h>
16 #include <File.h>
17 #include <List.h>
18 #include <Node.h>
19 #include <Path.h>
20 #include <String.h>
21 #include <fs_attr.h>
22 #include <fs_index.h>
23 #include <fs_info.h>
26 extern const char *__progname;
27 static const char *kProgramName = __progname;
29 bool gRecursive = false; // enter directories recursively
30 bool gVerbose = false;
31 char *gAttrPattern;
32 bool gIsPattern = false;
33 bool gFromVolume = false; // copy indices from another volume
34 BList gAttrList; // list of indices of that volume
37 class Attribute {
38 public:
39 Attribute(const char *name);
40 ~Attribute();
42 status_t ReadFromFile(BNode *node);
43 status_t WriteToFile(BNode *node);
44 status_t RemoveFromFile(BNode *node);
46 const char *Name() const { return fName.String(); }
47 type_code Type() const { return fType; }
48 size_t Length() const { return fLength; }
50 protected:
51 BString fName;
52 type_code fType;
53 void *fBuffer;
54 size_t fLength;
58 Attribute::Attribute(const char *name)
60 fName(name),
61 fBuffer(NULL),
62 fLength(0)
67 Attribute::~Attribute()
69 free(fBuffer);
73 status_t
74 Attribute::ReadFromFile(BNode *node)
76 attr_info info;
77 status_t status = node->GetAttrInfo(fName.String(), &info);
78 if (status != B_OK)
79 return status;
81 fType = info.type;
82 fLength = info.size;
84 if ((fBuffer = malloc(fLength)) == NULL)
85 return B_NO_MEMORY;
87 ssize_t bytesRead = node->ReadAttr(fName.String(), fType, 0, fBuffer,
88 fLength);
89 if (bytesRead < B_OK)
90 return bytesRead;
91 if (bytesRead < (ssize_t)fLength)
92 return B_IO_ERROR;
94 return B_OK;
98 status_t
99 Attribute::WriteToFile(BNode *node)
101 ssize_t bytesWritten = node->WriteAttr(fName.String(), fType, 0, fBuffer,
102 fLength);
103 if (bytesWritten < B_OK)
104 return bytesWritten;
105 if (bytesWritten < (ssize_t)fLength)
106 return B_IO_ERROR;
108 return B_OK;
112 status_t
113 Attribute::RemoveFromFile(BNode *node)
115 return node->RemoveAttr(fName.String());
119 // #pragma mark -
122 bool
123 nameMatchesPattern(char *name)
125 if (!gIsPattern)
126 return !strcmp(name,gAttrPattern);
128 // test the beginning
129 int i = 0;
130 for(; name[i]; i++) {
131 if (gAttrPattern[i] == '*')
132 break;
133 if (name[i] != gAttrPattern[i])
134 return false;
137 // test the end
138 int j = strlen(name) - 1;
139 int k = strlen(gAttrPattern) - 1;
140 for(; j >= i && k >= i; j--, k--) {
141 if (gAttrPattern[k] == '*')
142 return true;
143 if (name[j] != gAttrPattern[k])
144 return false;
146 if (gAttrPattern[k] != '*')
147 return false;
149 return true;
153 bool
154 isAttrInList(char *name)
156 for (int32 index = gAttrList.CountItems();index-- > 0;) {
157 const char *attr = (const char *)gAttrList.ItemAt(index);
158 if (!strcmp(attr, name))
159 return true;
161 return false;
165 void
166 handleFile(BEntry *entry, BNode *node)
168 // Recurse the directories
169 if (gRecursive && entry->IsDirectory()) {
170 BDirectory dir(entry);
171 BEntry entryIterator;
173 dir.Rewind();
174 while (dir.GetNextEntry(&entryIterator, false) == B_OK) {
175 BNode innerNode;
176 handleFile(&entryIterator, &innerNode);
179 // also rewrite the attributes of the directory
182 char name[B_FILE_NAME_LENGTH];
183 entry->GetName(name);
185 status_t status = node->SetTo(entry);
186 if (status != B_OK) {
187 fprintf(stderr, "%s: could not open \"%s\": %s\n", kProgramName, name,
188 strerror(status));
189 return;
192 // rewrite file attributes
194 char attrName[B_ATTR_NAME_LENGTH];
195 Attribute *attr;
196 BList list;
198 // building list
199 node->RewindAttrs();
200 while (node->GetNextAttrName(attrName) == B_OK) {
201 if (gFromVolume) {
202 if (!isAttrInList(attrName))
203 continue;
204 } else if (!nameMatchesPattern(attrName))
205 continue;
207 attr = new(std::nothrow) Attribute(attrName);
208 if (attr == NULL) {
209 fprintf(stderr, "%s: out of memory.\n", kProgramName);
210 exit(1);
213 status = attr->ReadFromFile(node);
214 if (status != B_OK) {
215 fprintf(stderr, "%s: could not read attribute \"%s\" of file "
216 "\"%s\": %s\n", kProgramName, attrName, name, strerror(status));
217 delete attr;
218 continue;
220 if (gVerbose) {
221 printf("%s: read attribute '%s' (%ld bytes of data)\n", name,
222 attrName, attr->Length());
224 if (!list.AddItem(attr)) {
225 fprintf(stderr, "%s: out of memory.\n", kProgramName);
226 exit(1);
229 if (!gFromVolume) {
230 // creates index to that attribute if necessary
231 entry_ref ref;
232 if (entry->GetRef(&ref) == B_OK) {
233 index_info indexInfo;
234 if (fs_stat_index(ref.device, attrName, &indexInfo) != B_OK)
235 fs_create_index(ref.device, attrName, attr->Type(), 0);
240 // remove attrs
241 for (int32 i = list.CountItems(); i-- > 0;) {
242 attr = static_cast<Attribute *>(list.ItemAt(i));
243 if (attr->RemoveFromFile(node) != B_OK) {
244 fprintf(stderr, "%s: could not remove attribute '%s' from file "
245 "'%s'.\n", kProgramName, attr->Name(), name);
249 // rewrite attrs and empty the list
250 while ((attr = static_cast<Attribute *>(list.RemoveItem((int32)0))) != NULL) {
251 // write attribute back to file
252 status = attr->WriteToFile(node);
253 if (status != B_OK) {
254 fprintf(stderr, "%s: could not write attribute '%s' to file \"%s\":"
255 " %s\n", kProgramName, attr->Name(), name, strerror(status));
256 } else if (gVerbose) {
257 printf("%s: wrote attribute '%s' (%ld bytes of data)\n", name,
258 attr->Name(), attr->Length());
261 delete attr;
266 void
267 copyIndicesFromVolume(const char *path, BEntry &to)
269 entry_ref ref;
270 if (to.GetRef(&ref) != B_OK) {
271 fprintf(stderr, "%s: Could not open target volume.\n", kProgramName);
272 return;
275 dev_t targetDevice = ref.device;
276 dev_t sourceDevice = dev_for_path(path);
277 if (sourceDevice < B_OK) {
278 fprintf(stderr, "%s: Could not open source volume: %s\n", kProgramName,
279 strerror(sourceDevice));
280 return;
283 DIR *indexDirectory = fs_open_index_dir(sourceDevice);
284 if (indexDirectory == NULL)
285 return;
287 while (dirent *index = fs_read_index_dir(indexDirectory)) {
288 index_info indexInfo;
289 if (fs_stat_index(sourceDevice, index->d_name, &indexInfo) != B_OK) {
290 fprintf(stderr, "%s: Could not get information about index "
291 "\"%s\": %s\n", kProgramName, index->d_name, strerror(errno));
292 continue;
295 if (fs_create_index(targetDevice, index->d_name, indexInfo.type, 0)
296 == -1 && errno != B_FILE_EXISTS && errno != B_BAD_VALUE) {
297 fprintf(stderr, "Could not create index '%s' (type = %" B_PRIu32
298 "): %s\n", index->d_name, indexInfo.type, strerror(errno));
299 } else
300 gAttrList.AddItem(strdup(index->d_name));
302 fs_close_index_dir(indexDirectory);
306 void
307 printUsage(char *cmd)
309 printf("usage: %s [-rvf] attr <list of filenames and/or directories>\n"
310 " -r\tenter directories recursively\n"
311 " -v\tverbose output\n"
312 " -f\tcreate/update all indices from the source volume,\n\t\"attr\" is "
313 "the path to the source volume\n", cmd);
318 main(int argc, char **argv)
320 char *cmd = argv[0];
322 if (argc < 3) {
323 printUsage(cmd);
324 return 1;
327 while (*++argv && **argv == '-') {
328 for (int i = 1; (*argv)[i]; i++) {
329 switch ((*argv)[i]) {
330 case 'f':
331 gFromVolume = true;
332 break;
333 case 'r':
334 gRecursive = true;
335 break;
336 case 'v':
337 gVerbose = true;
338 break;
339 default:
340 printUsage(cmd);
341 return(1);
345 gAttrPattern = *argv;
346 if (strchr(gAttrPattern,'*'))
347 gIsPattern = true;
349 while (*++argv) {
350 BEntry entry(*argv);
351 BNode node;
353 if (entry.InitCheck() == B_OK) {
354 if (gFromVolume)
355 copyIndicesFromVolume(gAttrPattern, entry);
356 handleFile(&entry, &node);
357 } else
358 fprintf(stderr, "%s: could not find \"%s\".\n", kProgramName, *argv);
361 return 0;