From 88cfea9fc27bfa62c294b5234005a61337580d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 30 Apr 2009 12:56:45 +0000 Subject: [PATCH] * Added a version of reindex that works under Haiku. Changes made to the original version: - removed the BFS bug work-around to create two temporary files first; this work around is not needed in our BFS implementation. - improved error output. - remove attributes before rewriting them. This is needed as BFS won't update the indices anymore if the attribute has not actually been changed. - applied our coding style. * This also fixes bug #3843. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30511 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/jam/HaikuImage | 11 +- src/bin/Jamfile | 1 + src/bin/reindex.cpp | 361 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 369 insertions(+), 4 deletions(-) create mode 100644 src/bin/reindex.cpp diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 2f535b8577..84738adcd9 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -43,10 +43,13 @@ SYSTEM_BIN = "[" addattr alert arp base64 basename bash bc beep bootman bzip2 listport listres listsem listusb ln locate logger login logname ls lsindex makebootable md5sum merge mimeset mkdos mkdir mkfifo mkfs mkindex modifiers mount mount_nfs mountvolume mv - nc netstat nl nohup od open passwd paste - patch pathchk pc ping play playfile playsound playwav pr prio printenv - printf profile ps ptx pwd query quit rc readlink release renice rescan rlog - rm rmattr rmindex rmdir roster route + nc netstat nl nohup + od open + passwd paste patch pathchk pc ping play playfile playsound playwav pr prio + printenv printf profile ps ptx pwd + query quit + rc readlink reindex release renice rescan rlog rm rmattr rmindex rmdir roster + route safemode screen_blanker screenmode sed setdecor settype setversion setvolume seq sha1sum shar shred shuf shutdown sleep sort spamdbm split stat strace stty su sum sync sysinfo diff --git a/src/bin/Jamfile b/src/bin/Jamfile index 2ae4e2f7bc..7b97b04d9e 100644 --- a/src/bin/Jamfile +++ b/src/bin/Jamfile @@ -95,6 +95,7 @@ StdBinCommands play.cpp query.cpp quit.cpp + reindex.cpp roster.cpp setdecor.cpp settype.cpp diff --git a/src/bin/reindex.cpp b/src/bin/reindex.cpp new file mode 100644 index 0000000000..8d386ca375 --- /dev/null +++ b/src/bin/reindex.cpp @@ -0,0 +1,361 @@ +/* + * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. + * This file may be used under the terms of the MIT License. + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern const char *__progname; +static const char *kProgramName = __progname; + +bool gRecursive = false; // enter directories recursively +bool gVerbose = false; +char *gAttrPattern; +bool gIsPattern = false; +bool gFromVolume = false; // copy indices from another volume +BList gAttrList; // list of indices of that volume + + +class Attribute { +public: + Attribute(const char *name); + ~Attribute(); + + status_t ReadFromFile(BNode *node); + status_t WriteToFile(BNode *node); + status_t RemoveFromFile(BNode *node); + + const char *Name() const { return fName.String(); } + type_code Type() const { return fType; } + size_t Length() const { return fLength; } + +protected: + BString fName; + type_code fType; + void *fBuffer; + size_t fLength; +}; + + +Attribute::Attribute(const char *name) + : + fName(name), + fBuffer(NULL), + fLength(0) +{ +} + + +Attribute::~Attribute() +{ + free(fBuffer); +} + + +status_t +Attribute::ReadFromFile(BNode *node) +{ + attr_info info; + status_t status = node->GetAttrInfo(fName.String(), &info); + if (status != B_OK) + return status; + + fType = info.type; + fLength = info.size; + + if ((fBuffer = malloc(fLength)) == NULL) + return B_NO_MEMORY; + + ssize_t bytesRead = node->ReadAttr(fName.String(), fType, 0, fBuffer, + fLength); + if (bytesRead < B_OK) + return bytesRead; + if (bytesRead < (ssize_t)fLength) + return B_IO_ERROR; + + return B_OK; +} + + +status_t +Attribute::WriteToFile(BNode *node) +{ + ssize_t bytesWritten = node->WriteAttr(fName.String(), fType, 0, fBuffer, + fLength); + if (bytesWritten < B_OK) + return bytesWritten; + if (bytesWritten < (ssize_t)fLength) + return B_IO_ERROR; + + return B_OK; +} + + +status_t +Attribute::RemoveFromFile(BNode *node) +{ + return node->RemoveAttr(fName.String()); +} + + +// #pragma mark - + + +bool +nameMatchesPattern(char *name) +{ + if (!gIsPattern) + return !strcmp(name,gAttrPattern); + + // test the beginning + int i = 0; + for(; name[i]; i++) { + if (gAttrPattern[i] == '*') + break; + if (name[i] != gAttrPattern[i]) + return false; + } + + // test the end + int j = strlen(name) - 1; + int k = strlen(gAttrPattern) - 1; + for(; j >= i && k >= i; j--, k--) { + if (gAttrPattern[k] == '*') + return true; + if (name[j] != gAttrPattern[k]) + return false; + } + if (gAttrPattern[k] != '*') + return false; + + return true; +} + + +bool +isAttrInList(char *name) +{ + for (int32 index = gAttrList.CountItems();index-- > 0;) { + const char *attr = (const char *)gAttrList.ItemAt(index); + if (!strcmp(attr, name)) + return true; + } + return false; +} + + +void +handleFile(BEntry *entry, BNode *node) +{ + // Recurse the directories + if (gRecursive && entry->IsDirectory()) { + BDirectory dir(entry); + BEntry entryIterator; + + dir.Rewind(); + while (dir.GetNextEntry(&entryIterator, false) == B_OK) { + BNode innerNode; + handleFile(&entryIterator, &innerNode); + } + return; + } + + char name[B_FILE_NAME_LENGTH]; + entry->GetName(name); + + status_t status = node->SetTo(entry); + if (status != B_OK) { + fprintf(stderr, "%s: could not open \"%s\": %s\n", kProgramName, name, + strerror(status)); + return; + } + + // rewrite file attributes + + char attrName[B_ATTR_NAME_LENGTH]; + Attribute *attr; + BList list; + + // building list + node->RewindAttrs(); + while (node->GetNextAttrName(attrName) == B_OK) { + if (gFromVolume) { + if (!isAttrInList(attrName)) + continue; + } else if (!nameMatchesPattern(attrName)) + continue; + + attr = new(std::nothrow) Attribute(attrName); + if (attr == NULL) { + fprintf(stderr, "%s: out of memory.\n", kProgramName); + exit(1); + } + + status = attr->ReadFromFile(node); + if (status != B_OK) { + fprintf(stderr, "%s: could not read attribute \"%s\" of file " + "\"%s\": %s\n", kProgramName, attrName, name, strerror(status)); + delete attr; + continue; + } + if (gVerbose) { + printf("%s: read attribute '%s' (%ld bytes of data)\n", name, + attrName, attr->Length()); + } + if (!list.AddItem(attr)) { + fprintf(stderr, "%s: out of memory.\n", kProgramName); + exit(1); + } + + if (!gFromVolume) { + // creates index to that attribute if necessary + entry_ref ref; + if (entry->GetRef(&ref) == B_OK) { + index_info indexInfo; + if (fs_stat_index(ref.device, attrName, &indexInfo) != B_OK) + fs_create_index(ref.device, attrName, attr->Type(), 0); + } + } + } + + // remove attrs + for (int32 i = list.CountItems(); i-- > 0;) { + attr = static_cast(list.ItemAt(i)); + if (attr->RemoveFromFile(node) != B_OK) { + fprintf(stderr, "%s: could not remove attribute '%s' from file " + "'%s'.\n", kProgramName, attr->Name(), name); + } + } + + // rewrite attrs and empty the list + while ((attr = static_cast(list.RemoveItem(0L))) != NULL) { + // write attribute back to file + status = attr->WriteToFile(node); + if (status != B_OK) { + fprintf(stderr, "%s: could not write attribute '%s' to file \"%s\":" + " %s\n", kProgramName, attr->Name(), name, strerror(status)); + } else if (gVerbose) { + printf("%s: wrote attribute '%s' (%ld bytes of data)\n", name, + attr->Name(), attr->Length()); + } + + delete attr; + } +} + + +void +copyIndicesFromVolume(const char *path, BEntry &to) +{ + entry_ref ref; + if (to.GetRef(&ref) != B_OK) { + fprintf(stderr, "%s: Could not open target volume.\n", kProgramName); + return; + } + + dev_t targetDevice = ref.device; + dev_t sourceDevice = dev_for_path(path); + if (sourceDevice < B_OK) { + fprintf(stderr, "%s: Could not open source volume: %s\n", kProgramName, + strerror(sourceDevice)); + return; + } + + DIR *indexDirectory = fs_open_index_dir(sourceDevice); + if (indexDirectory == NULL) + return; + + while (dirent *index = fs_read_index_dir(indexDirectory)) { + index_info indexInfo; + if (fs_stat_index(sourceDevice, index->d_name, &indexInfo) != B_OK) { + fprintf(stderr, "%s: Could not get information about index " + "\"%s\": %s\n", kProgramName, index->d_name, strerror(errno)); + continue; + } + + if (fs_create_index(targetDevice, index->d_name, indexInfo.type, 0) + == -1 && errno != B_FILE_EXISTS && errno != B_BAD_VALUE) { + fprintf(stderr, "Could not create index '%s' (type = %lu): %s\n", + index->d_name, indexInfo.type, strerror(errno)); + } else + gAttrList.AddItem(strdup(index->d_name)); + } + fs_close_index_dir(indexDirectory); +} + + +void +printUsage(char *cmd) +{ + printf("usage: %s [-rvf] attr \n" + " -r\tenter directories recursively\n" + " -v\tverbose output\n" + " -f\tcreate/update all indices from the source volume,\n\t\"attr\" is " + "the path to the source volume\n", cmd); +} + + +int +main(int argc, char **argv) +{ + char *cmd = argv[0]; + + if (argc < 3) { + printUsage(cmd); + return 1; + } + + while (*++argv && **argv == '-') { + for (int i = 1; (*argv)[i]; i++) { + switch ((*argv)[i]) { + case 'f': + gFromVolume = true; + break; + case 'r': + gRecursive = true; + break; + case 'v': + gVerbose = true; + break; + default: + printUsage(cmd); + return(1); + } + } + } + gAttrPattern = *argv; + if (strchr(gAttrPattern,'*')) + gIsPattern = true; + + while (*++argv) { + BEntry entry(*argv); + BNode node; + + if (entry.InitCheck() == B_OK) { + if (gFromVolume) + copyIndicesFromVolume(gAttrPattern, entry); + handleFile(&entry, &node); + } else + fprintf(stderr, "%s: could not find \"%s\".\n", kProgramName, *argv); + } + + return 0; +}