* Copyright 2002-2006, Haiku Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Tyler Dauwalder
* Ingo Weinhold, bonefish@users.sf.net
*/
\file MimeUpdateThread.cpp
MimeUpdateThread implementation
*/
#include "MimeUpdateThread.h"
#include <stdio.h>
#include <Directory.h>
#include <Message.h>
#include <Path.h>
#include <RegistrarDefs.h>
#include <Volume.h>
#include <storage_support.h>
#define DBG(x)
#define OUT printf
namespace BPrivate {
namespace Storage {
namespace Mime {
\brief RegistrarThread class implementing the common functionality of
update_mime_info() and create_app_meta_mime()
*/
If \a replyee is non-NULL and construction succeeds, the MimeThreadObject
assumes resposibility for its deletion.
Also, if \c non-NULL, \a replyee is expected to be a
\c B_REG_MIME_UPDATE_MIME_INFO or a \c B_REG_MIME_CREATE_APP_META_MIME
message with a \c true \c "synchronous" field detached from the registrar's
mime manager looper (though this is not verified).
The message will be replied to at the end of the thread's execution.
*/
MimeUpdateThread::MimeUpdateThread(const char *name, int32 priority,
Database *database, BMessenger managerMessenger, const entry_ref *root,
bool recursive, int32 force, BMessage *replyee)
:
RegistrarThread(name, priority, managerMessenger),
fDatabase(database),
fRoot(root ? *root : entry_ref()),
fRecursive(recursive),
fForce(force),
fReplyee(replyee),
fStatus(root ? B_OK : B_BAD_VALUE)
{
}
If the object was properly initialized (i.e. InitCheck() returns \c B_OK)
and the replyee message passed to the constructor was \c non-NULL, the
replyee message is deleted.
*/
MimeUpdateThread::~MimeUpdateThread()
{
if (InitCheck() == B_OK)
delete fReplyee;
}
*/
status_t
MimeUpdateThread::InitCheck()
{
status_t err = RegistrarThread::InitCheck();
if (!err)
err = fStatus;
return err;
}
create_app_meta_mime(), namely iterating through the filesystem and
updating entries.
*/
status_t
MimeUpdateThread::ThreadFunction()
{
status_t err = InitCheck();
try {
if (!err)
err = UpdateEntry(&fRoot);
} catch (...) {
err = B_ERROR;
}
if (fReplyee) {
BMessage reply(B_REG_RESULT);
status_t error = reply.AddInt32("result", err);
err = error;
if (!err)
err = fReplyee->SendReply(&reply);
}
fIsFinished = true;
if (!err) {
BMessage msg(B_REG_MIME_UPDATE_THREAD_FINISHED);
status_t error = fManagerMessenger.SendMessage(&msg, (BHandler*)NULL,
500000);
if (error)
OUT("WARNING: ThreadManager::ThreadEntryFunction(): Termination"
" notification failed with error 0x%" B_PRIx32 "\n", error);
}
DBG(OUT("(id: %ld) exiting mime update thread with result 0x%" B_PRIx32
"\n", find_thread(NULL), err));
return err;
}
if not (or if an error occurs while determining).
Device numbers and their corresponding support info are cached in
a std::list to save unnecessarily \c statvfs()ing devices that have
already been statvfs()ed (which might otherwise happen quite often
for a device that did in fact support attributes).
\return
- \c true: The device supports attributes
- \c false: The device does not support attributes, or there was an
error while determining
*/
bool
MimeUpdateThread::DeviceSupportsAttributes(dev_t device)
{
std::list< std::pair<dev_t,bool> >::iterator i;
for (i = fAttributeSupportList.begin();
i != fAttributeSupportList.end(); i++)
{
if (i->first == device)
return i->second;
}
bool result = false;
BVolume volume;
status_t err = volume.SetTo(device);
if (!err) {
result = volume.KnowsAttr();
std::pair<dev_t,bool> p(device, result);
if (result)
fAttributeSupportList.push_front(p);
else
fAttributeSupportList.push_back(p);
}
return result;
}
child entries if the entry is a directory and \c fRecursive is true.
*/
status_t
MimeUpdateThread::UpdateEntry(const entry_ref *ref)
{
status_t err = ref ? B_OK : B_BAD_VALUE;
bool entryIsDir = false;
if (!err && fShouldExit)
err = B_CANCELED;
if (!err && (device_is_root_device(ref->device)
|| DeviceSupportsAttributes(ref->device))) {
if (!err) {
DoMimeUpdate(ref, &entryIsDir);
}
if (!err && fRecursive && entryIsDir) {
BDirectory dir;
err = dir.SetTo(ref);
if (!err) {
entry_ref childRef;
while (!err) {
err = dir.GetNextRef(&childRef);
if (err) {
if (err == B_ENTRY_NOT_FOUND)
err = B_OK;
break;
} else
err = UpdateEntry(&childRef);
}
}
}
}
return err;
}
}
}
}