/* * 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 #include #include #include #include #include #include //#define DBG(x) x #define DBG(x) #define OUT printf namespace BPrivate { namespace Storage { namespace Mime { /*! \class MimeUpdateThread \brief RegistrarThread class implementing the common functionality of update_mime_info() and create_app_meta_mime() */ /*! \brief Creates a new MimeUpdateThread object. 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) { } /*! \brief Destroys the MimeUpdateThread object. 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() { // delete our acquired BMessage if (InitCheck() == B_OK) delete fReplyee; } /*! \brief Returns the initialization status of the object */ status_t MimeUpdateThread::InitCheck() { status_t err = RegistrarThread::InitCheck(); if (!err) err = fStatus; return err; } /*! \brief Implements the common functionality of update_mime_info() and create_app_meta_mime(), namely iterating through the filesystem and updating entries. */ status_t MimeUpdateThread::ThreadFunction() { status_t err = InitCheck(); // The registrar is using this, too, so we better make sure we // don't run into troubles try { // Do the updates if (!err) err = UpdateEntry(&fRoot); } catch (...) { err = B_ERROR; } // Send a reply if we have a message to reply to if (fReplyee) { BMessage reply(B_REG_RESULT); status_t error = reply.AddInt32("result", err); err = error; if (!err) err = fReplyee->SendReply(&reply); } // Flag ourselves as finished fIsFinished = true; // Notify the thread manager to make a cleanup run 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; } /*! \brief Returns true if the given device supports attributes, false 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) { // See if an entry for this device already exists std::list< std::pair >::iterator i; for (i = fAttributeSupportList.begin(); i != fAttributeSupportList.end(); i++) { if (i->first == device) return i->second; } bool result = false; // If we get here, no such device is yet in our list, // so we attempt to remedy the situation BVolume volume; status_t err = volume.SetTo(device); if (!err) { result = volume.KnowsAttr(); // devices supporting attributes are likely to be queried // again, devices not supporting attributes are not std::pair p(device, result); if (result) fAttributeSupportList.push_front(p); else fAttributeSupportList.push_back(p); } return result; } // UpdateEntry /*! \brief Updates the given entry and then recursively updates all the entry's 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; // Look to see if we're being terminated if (!err && fShouldExit) err = B_CANCELED; // Before we update, make sure this entry lives on a device that supports // attributes. If not, we skip it and any of its children for // updates (we don't signal an error, however). //BPath path(ref); //printf("Updating '%s' (%s)... \n", path.Path(), // (DeviceSupportsAttributes(ref->device) ? "yes" : "no")); if (!err && (device_is_root_device(ref->device) || DeviceSupportsAttributes(ref->device))) { // Update this entry if (!err) { // R5 appears to ignore whether or not the update succeeds. DoMimeUpdate(ref, &entryIsDir); } // If we're recursing and this is a directory, update // each of the directory's children as well if (!err && fRecursive && entryIsDir) { BDirectory dir; err = dir.SetTo(ref); if (!err) { entry_ref childRef; while (!err) { err = dir.GetNextRef(&childRef); if (err) { // If we've come to the end of the directory listing, // it's not an error. if (err == B_ENTRY_NOT_FOUND) err = B_OK; break; } else err = UpdateEntry(&childRef); } } } } return err; } } // namespace Mime } // namespace Storage } // namespace BPrivate