* 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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -95,6 +95,7 @@ StdBinCommands
|
||||
play.cpp
|
||||
query.cpp
|
||||
quit.cpp
|
||||
reindex.cpp
|
||||
roster.cpp
|
||||
setdecor.cpp
|
||||
settype.cpp
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright 2001-2009, Axel Dörfler, [email protected].
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <List.h>
|
||||
#include <Node.h>
|
||||
#include <Path.h>
|
||||
#include <String.h>
|
||||
#include <fs_attr.h>
|
||||
#include <fs_index.h>
|
||||
#include <fs_info.h>
|
||||
|
||||
|
||||
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<Attribute *>(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<Attribute *>(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 <list of filenames and/or directories>\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;
|
||||
}
|
||||
Reference in New Issue
Block a user