1/*
2 * Copyright 2002-2006, Haiku Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Tyler Dauwalder
7 *		Ingo Weinhold, bonefish@users.sf.net
8 */
9
10/*!
11	\file MimeUpdateThread.cpp
12	MimeUpdateThread implementation
13*/
14
15#include <stdio.h>
16
17#include <Directory.h>
18#include <Message.h>
19#include <Path.h>
20#include <RegistrarDefs.h>
21#include <Volume.h>
22
23#include <storage_support.h>
24#include "mime/MimeUpdateThread.h"
25
26//#define DBG(x) x
27#define DBG(x)
28#define OUT printf
29
30
31namespace BPrivate {
32namespace Storage {
33
34#if (defined(__BEOS__) || defined(__HAIKU__))
35// device_is_root_device
36bool
37device_is_root_device(dev_t device)
38{
39	return device == 1;
40}
41#endif
42
43namespace Mime {
44
45/*!	\class MimeUpdateThread
46	\brief RegistrarThread class implementing the common functionality of
47	update_mime_info() and create_app_meta_mime()
48*/
49
50// constructor
51/*! \brief Creates a new MimeUpdateThread object.
52
53	If \a replyee is non-NULL and construction succeeds, the MimeThreadObject
54	assumes resposibility for its deletion.
55
56	Also, if \c non-NULL, \a replyee is expected to be a \c B_REG_MIME_UPDATE_MIME_INFO
57	or a \c B_REG_MIME_CREATE_APP_META_MIME	message with a \c true \c "synchronous"
58	field detached from the registrar's	mime manager looper (though this is not verified).
59	The message will be	replied to at the end of the thread's execution.
60*/
61MimeUpdateThread::MimeUpdateThread(const char *name, int32 priority,
62	BMessenger managerMessenger, const entry_ref *root, bool recursive,
63	int32 force, BMessage *replyee)
64	: /*RegistrarThread(name, priority, managerMessenger)
65	,*/ fRoot(root ? *root : entry_ref())
66	, fRecursive(recursive)
67	, fForce(force)
68	, fReplyee(replyee)
69	, fStatus(root ? B_OK : B_BAD_VALUE)
70{
71}
72
73// destructor
74/*!	\brief Destroys the MimeUpdateThread object.
75
76	If the object was properly initialized (i.e. InitCheck() returns \c B_OK) and
77	the replyee message passed to the constructor was \c non-NULL, the replyee
78	message is deleted.
79*/
80MimeUpdateThread::~MimeUpdateThread()
81{
82	// delete our acquired BMessage
83	if (InitCheck() == B_OK)
84		delete fReplyee;
85}
86
87// InitCheck()
88/*! \brief Returns the initialization status of the object
89*/
90status_t
91MimeUpdateThread::InitCheck()
92{
93	return fStatus;
94}
95
96// ThreadFunction
97/*! \brief Implements the common functionality of update_mime_info() and
98	create_app_meta_mime(), namely iterating through the filesystem and
99	updating entries.
100*/
101status_t
102MimeUpdateThread::ThreadFunction()
103{
104	status_t err = InitCheck();
105	// Do the updates
106	if (!err)
107		err = UpdateEntry(&fRoot);
108/*	// Send a reply if we have a message to reply to
109	if (fReplyee) {
110		BMessage reply(B_REG_RESULT);
111		status_t error = reply.AddInt32("result", err);
112		err = error;
113		if (!err)
114			err = fReplyee->SendReply(&reply);
115	}
116	// Flag ourselves as finished
117	fIsFinished = true;
118	// Notify the thread manager to make a cleanup run
119	if (!err) {
120		BMessage msg(B_REG_MIME_UPDATE_THREAD_FINISHED);
121		status_t error = fManagerMessenger.SendMessage(&msg, (BHandler*)NULL, 500000);
122		if (error)
123			OUT("WARNING: ThreadManager::ThreadEntryFunction(): Termination notification "
124				"failed with error 0x%lx\n", error);
125	}
126	DBG(OUT("(id: %ld) exiting mime update thread with result 0x%lx\n",
127		find_thread(NULL), err));
128*/	return err;
129}
130
131// DeviceSupportsAttributes
132/*! \brief Returns true if the given device supports attributes, false
133	if not (or if an error occurs while determining).
134
135	Device numbers and their corresponding support info are cached in
136	a std::list to save unnecessarily \c statvfs()ing devices that have
137	already been statvfs()ed (which might otherwise happen quite often
138	for a device that did in fact support attributes).
139
140	\return
141	- \c true: The device supports attributes
142	- \c false: The device does not support attributes, or there was an
143	            error while determining
144*/
145bool
146MimeUpdateThread::DeviceSupportsAttributes(dev_t device)
147{
148	return true;
149}
150
151// UpdateEntry
152/*! \brief Updates the given entry and then recursively updates all the entry's child
153	entries	if the entry is a directory and \c fRecursive is true.
154*/
155status_t
156MimeUpdateThread::UpdateEntry(const entry_ref *ref)
157{
158	status_t err = ref ? B_OK : B_BAD_VALUE;
159	bool entryIsDir = false;
160
161	// Look to see if we're being terminated
162//	if (!err && fShouldExit)
163//		err = B_CANCELED;
164
165	// Before we update, make sure this entry lives on a device that supports
166	// attributes. If not, we skip it and any of its children for
167	// updates (we don't signal an error, however).
168
169//BPath path(ref);
170//printf("Updating '%s' (%s)... \n", path.Path(),
171//	(DeviceSupportsAttributes(ref->device) ? "yes" : "no"));
172
173	if (!err
174	      && (device_is_root_device(ref->device)
175	            || DeviceSupportsAttributes(ref->device))) {
176		// Update this entry
177		if (!err)
178			err = DoMimeUpdate(ref, &entryIsDir);
179
180		// If we're recursing and this is a directory, update
181		// each of the directory's children as well
182		if (!err && fRecursive && entryIsDir) {
183			BDirectory dir;
184			err = dir.SetTo(ref);
185			if (!err) {
186				entry_ref childRef;
187				while (!err) {
188					err = dir.GetNextRef(&childRef);
189					if (err) {
190						// If we've come to the end of the directory listing,
191						// it's not an error.
192						if (err == B_ENTRY_NOT_FOUND)
193						 	err = B_OK;
194						break;
195					} else {
196						err = UpdateEntry(&childRef);
197					}
198				}
199			}
200		}
201	}
202	return err;
203}
204
205}	// namespace Mime
206}	// namespace Storage
207}	// namespace BPrivate
208