Removed the old, nicely working, DiskDevice API support from the registrar. We're going to reimplement it in the kernel.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3429 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2003-06-04 21:20:23 +00:00
parent c41e89d3da
commit 32453e90e0
12 changed files with 1 additions and 2656 deletions

View File

@ -1,356 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
#include <NodeMonitor.h>
#include <RegistrarDefs.h>
#include "DiskDeviceManager.h"
#include "Debug.h"
#include "EventMaskWatcher.h"
#include "EventQueue.h"
#include "MessageEvent.h"
#include "RDiskDevice.h"
#include "RDiskDeviceList.h"
#include "RPartition.h"
#include "RSession.h"
// priorities of the different message kinds
enum {
REQUEST_PRIORITY = 0,
RESCAN_PRIORITY = 5,
NODE_MONITOR_PRIORITY = 10,
WATCHING_REQUEST_PRIORITY = 20,
};
// time interval between device rescans
static const bigtime_t kRescanEventInterval = 5000000;
// constructor
DiskDeviceManager::DiskDeviceManager(EventQueue *eventQueue)
: BLooper("disk device manager"),
fEventQueue(eventQueue),
fRescanEvent(NULL),
fDeviceListLock(),
fWatchingService(),
fVolumeList(BMessenger(this), fDeviceListLock),
fDeviceList(BMessenger(this), fDeviceListLock, fVolumeList,
&fWatchingService),
fMessageQueue(),
fWorker(-1),
fMessageCounter(-1),
fTerminating(false)
{
// set up the device list
fVolumeList.Dump();
fDeviceList.Rescan();
fDeviceList.Dump();
// start the worker thread
fMessageCounter = create_sem(0, "disk device manager msgcounter");
if (fMessageCounter >= 0) {
fWorker = spawn_thread(_WorkerEntry, "disk device manager worker",
B_NORMAL_PRIORITY, this);
if (fWorker >= 0)
resume_thread(fWorker);
}
// set up the rescan event
fRescanEvent = new MessageEvent(system_time() + kRescanEventInterval,
this, B_REG_ROSTER_DEVICE_RESCAN);
fRescanEvent->SetAutoDelete(false);
fEventQueue->AddEvent(fRescanEvent);
}
// destructor
DiskDeviceManager::~DiskDeviceManager()
{
// remove the rescan event from the event queue
fEventQueue->RemoveEvent(fRescanEvent);
// terminate the worker thread
fTerminating = true;
delete_sem(fMessageCounter);
int32 dummy;
wait_for_thread(fWorker, &dummy);
}
// MessageReceived
void
DiskDeviceManager::MessageReceived(BMessage *message)
{
switch (message->what) {
case B_REG_NEXT_DISK_DEVICE:
case B_REG_GET_DISK_DEVICE:
case B_REG_UPDATE_DISK_DEVICE:
DetachCurrentMessage();
if (!_PushMessage(message, REQUEST_PRIORITY))
delete message;
break;
case B_REG_DEVICE_START_WATCHING:
case B_REG_DEVICE_STOP_WATCHING:
DetachCurrentMessage();
if (!_PushMessage(message, WATCHING_REQUEST_PRIORITY))
delete message;
break;
case B_REG_ROSTER_DEVICE_RESCAN:
DetachCurrentMessage();
if (!_PushMessage(message, RESCAN_PRIORITY))
delete message;
break;
case B_NODE_MONITOR:
DetachCurrentMessage();
if (!_PushMessage(message, NODE_MONITOR_PRIORITY))
delete message;
break;
default:
BLooper::MessageReceived(message);
break;
}
}
// _NextDiskDeviceRequest
void
DiskDeviceManager::_NextDiskDeviceRequest(BMessage *request)
{
FUNCTION_START();
Lock();
status_t error = B_OK;
int32 cookie = 0;
BMessage reply(B_REG_RESULT);
if (request->FindInt32("cookie", &cookie) == B_OK) {
// get next device
if (RDiskDevice *device = fDeviceList.DeviceWithID(cookie, false)) {
// archive device
BMessage deviceArchive;
SET_ERROR(error, device->Archive(&deviceArchive));
// add archived device and next cookie to reply message
if (error == B_OK)
SET_ERROR(error, reply.AddMessage("device", &deviceArchive));
if (error == B_OK)
SET_ERROR(error, reply.AddInt32("cookie", device->ID() + 1));
} else
error = B_ENTRY_NOT_FOUND;
} else
SET_ERROR(error, B_BAD_VALUE);
// add result and send reply
reply.AddInt32("result", error);
request->SendReply(&reply);
Unlock();
}
// _GetDiskDeviceRequest
void
DiskDeviceManager::_GetDiskDeviceRequest(BMessage *request)
{
Lock();
status_t error = B_OK;
// get the device
RDiskDevice *device = NULL;
int32 id = 0;
if (request->FindInt32("device_id", &id) == B_OK)
device = fDeviceList.DeviceWithID(id);
else if (request->FindInt32("session_id", &id) == B_OK) {
if (RSession *session = fDeviceList.SessionWithID(id))
device = session->Device();
} else if (request->FindInt32("partition_id", &id) == B_OK) {
if (RPartition *partition = fDeviceList.PartitionWithID(id))
device = partition->Device();
} else
error = B_BAD_VALUE;
// archive device and add it to the reply message
BMessage reply(B_REG_RESULT);
if (device) {
BMessage deviceArchive;
error = device->Archive(&deviceArchive);
if (error == B_OK)
error = reply.AddMessage("device", &deviceArchive);
} else // requested object not found
error = B_ENTRY_NOT_FOUND;
// add result and send reply
reply.AddInt32("result", error);
request->SendReply(&reply);
Unlock();
}
// _UpdateDiskDeviceRequest
void
DiskDeviceManager::_UpdateDiskDeviceRequest(BMessage *request)
{
Lock();
status_t error = B_OK;
// get the device and check the object is up to date
bool upToDate = false;
RDiskDevice *device = NULL;
int32 id = 0;
int32 changeCounter = 0;
uint32 policy = 0;
if (request->FindInt32("change_counter", &changeCounter) != B_OK
|| request->FindInt32("update_policy", (int32*)&policy) != B_OK) {
// bad request request
SET_ERROR(error, B_BAD_VALUE);
} else if (request->FindInt32("device_id", &id) == B_OK) {
device = fDeviceList.DeviceWithID(id);
if (device)
upToDate = (device->ChangeCounter() == changeCounter);
PRINT(("DiskDeviceManager::_UpdateDiskDeviceRequest(): device id: %ld, "
"device: %p\n", id, device));
} else if (request->FindInt32("session_id", &id) == B_OK) {
if (RSession *session = fDeviceList.SessionWithID(id)) {
device = session->Device();
upToDate = (session->ChangeCounter() == changeCounter);
}
} else if (request->FindInt32("partition_id", &id) == B_OK) {
if (RPartition *partition = fDeviceList.PartitionWithID(id)) {
device = partition->Device();
upToDate = (partition->ChangeCounter() == changeCounter);
}
} else // bad request message
SET_ERROR(error, B_BAD_VALUE);
// archive device and add it to the reply message
BMessage reply(B_REG_RESULT);
if (device) {
if (policy == B_REG_DEVICE_UPDATE_DEVICE_CHANGED)
upToDate = (device->ChangeCounter() == changeCounter);
if (!upToDate && policy != B_REG_DEVICE_UPDATE_CHECK) {
BMessage deviceArchive;
error = device->Archive(&deviceArchive);
if (error == B_OK)
error = reply.AddMessage("device", &deviceArchive);
}
} else // requested object not found
error = B_ENTRY_NOT_FOUND;
// add result and send reply
if (error == B_OK)
error = reply.AddBool("up_to_date", upToDate);
reply.AddInt32("result", error);
request->SendReply(&reply);
Unlock();
}
// _StartWatchingRequest
void
DiskDeviceManager::_StartWatchingRequest(BMessage *request)
{
FUNCTION_START();
Lock();
status_t error = B_OK;
// get the parameters
BMessenger target;
uint32 events;
if (error == B_OK
&& (request->FindMessenger("target", &target) != B_OK
|| request->FindInt32("events", (int32*)&events) != B_OK)) {
SET_ERROR(error, B_BAD_VALUE);
}
// add the new watcher
if (error == B_OK) {
Watcher *watcher = new(nothrow) EventMaskWatcher(target, events);
if (watcher) {
if (!fWatchingService.AddWatcher(watcher)) {
SET_ERROR(error, B_NO_MEMORY);
delete watcher;
}
} else
SET_ERROR(error, B_NO_MEMORY);
}
// add result and send reply
BMessage reply(B_REG_RESULT);
reply.AddInt32("result", error);
request->SendReply(&reply);
Unlock();
};
// _StopWatchingRequest
void
DiskDeviceManager::_StopWatchingRequest(BMessage *request)
{
FUNCTION_START();
Lock();
status_t error = B_OK;
// get the parameters
BMessenger target;
if (error == B_OK && request->FindMessenger("target", &target) != B_OK)
error = B_BAD_VALUE;
// remove the watcher
if (error == B_OK) {
if (!fWatchingService.RemoveWatcher(target))
error = B_BAD_VALUE;
}
// add result and send reply
BMessage reply(B_REG_RESULT);
reply.AddInt32("result", error);
request->SendReply(&reply);
Unlock();
};
// _PushMessage
bool
DiskDeviceManager::_PushMessage(BMessage *message, int32 priority)
{
bool result = fMessageQueue.PushMessage(message, priority);
if (result)
release_sem(fMessageCounter);
return result;
}
// _PopMessage
BMessage *
DiskDeviceManager::_PopMessage()
{
BMessage *result = NULL;
status_t error = acquire_sem(fMessageCounter);
if (error == B_OK)
result = fMessageQueue.PopMessage();
return result;
}
// _WorkerEntry
int32
DiskDeviceManager::_WorkerEntry(void *parameters)
{
return static_cast<DiskDeviceManager*>(parameters)->_Worker();
}
// _Worker
int32
DiskDeviceManager::_Worker()
{
while (!fTerminating) {
if (BMessage *message = _PopMessage()) {
// dispatch the message
switch (message->what) {
case B_REG_NEXT_DISK_DEVICE:
_NextDiskDeviceRequest(message);
break;
case B_REG_GET_DISK_DEVICE:
_GetDiskDeviceRequest(message);
break;
case B_REG_UPDATE_DISK_DEVICE:
_UpdateDiskDeviceRequest(message);
break;
case B_REG_DEVICE_START_WATCHING:
_StartWatchingRequest(message);
break;
case B_REG_DEVICE_STOP_WATCHING:
_StopWatchingRequest(message);
break;
case B_REG_ROSTER_DEVICE_RESCAN:
fDeviceList.Rescan();
fRescanEvent->SetTime(system_time()
+ kRescanEventInterval);
fEventQueue->AddEvent(fRescanEvent);
break;
case B_NODE_MONITOR:
{
fVolumeList.HandleMessage(message);
break;
}
default:
// error
break;
}
delete message;
}
}
return 0;
}

View File

@ -1,19 +1,14 @@
SubDir OBOS_TOP src servers registrar ;
UsePublicHeaders app ;
UsePrivateHeaders $(DOT) ; # needed for disk_scanner.cpp
UsePrivateHeaders app ;
UsePrivateHeaders shared ;
UsePrivateHeaders storage ;
# needed as long as disk_scanner.cpp is compiled in
SEARCH_SOURCE += [ FDirName $(OBOS_TOP) src kernel libroot os ] ;
Server obos_registrar :
AppInfoList.cpp
ClipboardHandler.cpp
ClipboardTree.cpp
DiskDeviceManager.cpp
Event.cpp
EventMaskWatcher.cpp
EventQueue.cpp
@ -21,35 +16,18 @@ Server obos_registrar :
MessageHandler.cpp
MessageRunnerManager.cpp
MIMEManager.cpp
NodeMonitoring.cpp
PriorityMessageQueue.cpp
RDiskDevice.cpp
RDiskDeviceList.cpp
RecentApps.cpp
RecentEntries.cpp
Registrar.cpp
RosterAppInfo.cpp
RosterSettingsCharStream.cpp
RPartition.cpp
RSession.cpp
RVolumeList.cpp
TRoster.cpp
Watcher.cpp
WatchingService.cpp
# from .../libroot/os
disk_scanner.cpp
;
LinkSharedOSLibs obos_registrar :
<boot!home!config!lib>libopenbeos.so
<boot!home!config!lib>libkernelland_emu.so # needed for disk_scanner.cpp
stdc++.r4
be
;
# Helper needed for node watching
#
BinCommand NodeMonitor : NodeMonitor.cpp : be ;
Depends obos_registrar : NodeMonitor ;

View File

@ -1,145 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
#include <Application.h>
#include <Message.h>
#include <Messenger.h>
#include <NodeMonitor.h>
#include <ObjectList.h>
// Monitor
class Monitor : public BHandler {
public:
Monitor(BMessenger target);
virtual ~Monitor();
virtual void MessageReceived(BMessage *message);
BMessenger Target() const { return fTarget; }
private:
BMessenger fTarget;
};
// NodeMonitorApp
class NodeMonitorApp : public BApplication {
public:
NodeMonitorApp();
virtual ~NodeMonitorApp();
virtual void MessageReceived(BMessage *message);
private:
BObjectList<Monitor> fMonitors;
};
// Monitor
// constructor
Monitor::Monitor(BMessenger target)
: BHandler(),
fTarget(target)
{
}
// destructor
Monitor::~Monitor()
{
}
// MessageReceived
void
Monitor::MessageReceived(BMessage *message)
{
switch (message->what) {
case B_NODE_MONITOR:
fTarget.SendMessage(message);
break;
}
}
// NodeMonitorApp
// constructor
NodeMonitorApp::NodeMonitorApp()
: BApplication("application/x-vnd.obos-NodeMonitor"),
fMonitors(10, true)
{
}
// destructor
NodeMonitorApp::~NodeMonitorApp()
{
Lock();
for (int32 i = 0; Monitor *monitor = fMonitors.ItemAt(i); i++)
RemoveHandler(monitor);
Unlock();
}
// MessageReceived
void
NodeMonitorApp::MessageReceived(BMessage *message)
{
switch (message->what) {
case 'wtch':
{
status_t error = B_BAD_VALUE;
node_ref ref;
BMessenger target;
uint32 flags;
if (message->FindInt32("device", &ref.device) == B_OK
&& message->FindInt64("node", &ref.node) == B_OK
&& message->FindMessenger("target", &target) == B_OK
&& message->FindInt32("flags", (int32*)&flags) == B_OK) {
Monitor *monitor = new Monitor(target);
fMonitors.AddItem(monitor);
AddHandler(monitor);
error = watch_node(&ref, flags, monitor);
if (error != B_OK) {
RemoveHandler(monitor);
fMonitors.RemoveItem(monitor);
}
}
BMessage reply(B_SIMPLE_DATA);
reply.AddInt32("result", error);
message->SendReply(&reply);
break;
}
case 'hctw':
{
status_t error = B_BAD_VALUE;
BMessenger target;
if (message->FindMessenger("target", &target) == B_OK) {
error = B_OK;
for (int32 i = fMonitors.CountItems();
Monitor *monitor = fMonitors.ItemAt(i);
i--) {
if (monitor->Target() == target) {
error = stop_watching(monitor->Target());
RemoveHandler(monitor);
delete fMonitors.RemoveItemAt(i);
}
}
}
BMessage reply(B_SIMPLE_DATA);
reply.AddInt32("result", error);
message->SendReply(&reply);
break;
}
}
}
// main
int
main()
{
NodeMonitorApp app;
app.Run();
return 0;
}

View File

@ -1,226 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
// A fake implementation of the node monitoring functions.
// They start a remote application that functions as an adapter for the
// functions in libbe.so.
// Note: We can't use the node monitoring provided by libbe directly, since
// it makes sure, that the target is local using BMessenger::Target(), which
// can't work.
#include <stdlib.h>
#include <string.h>
#include <AppMisc.h>
#include <image.h>
#include <Locker.h>
#include <Message.h>
#include <Messenger.h>
#include <NodeMonitor.h>
#include <OS.h>
#include "Debug.h"
// NodeMonitor
class NodeMonitor {
public:
NodeMonitor();
~NodeMonitor();
status_t GetMessenger(BMessenger &monitor);
status_t WatchingRequest(const node_ref *node, uint32 flags,
BMessenger target, bool start);
private:
bool fInitialized;
status_t fStatus;
thread_id fThread;
team_id fTeam;
BMessenger fMessenger;
BLocker fLock;
};
static NodeMonitor gNodeMonitor;
// constructor
NodeMonitor::NodeMonitor()
: fInitialized(false),
fStatus(B_ERROR),
fThread(-1),
fTeam(-1),
fMessenger(),
fLock()
{
}
// destructor
NodeMonitor::~NodeMonitor()
{
fLock.Lock();
if (fInitialized) {
if (fMessenger.IsValid())
fMessenger.SendMessage(B_QUIT_REQUESTED);
else if (fThread >= 0)
kill_thread(fThread);
}
fLock.Unlock();
}
// GetMessenger
status_t
NodeMonitor::GetMessenger(BMessenger &monitor)
{
fLock.Lock();
if (!fInitialized) {
fInitialized = true;
// get NodeMonitor path
char path[B_PATH_NAME_LENGTH];
fStatus = BPrivate::get_app_path(path);
if (fStatus == B_OK) {
if (char *leaf = strstr(path, "obos_registrar")) {
strcpy(leaf, "../../bin/NodeMonitor");
} else
fStatus = B_ERROR;
}
// start the NodeMonitor
if (fStatus == B_OK) {
const char *argv[] = { path, NULL };
fThread = load_image(1, argv,
const_cast<const char**>(environ));
if (fThread >= 0) {
resume_thread(fThread);
thread_info info;
fStatus = get_thread_info(fThread, &info);
if (fStatus == B_OK)
fTeam = info.team;
} else
fStatus = fThread;
}
// find the app looper port
port_id port = -1;
if (fStatus == B_OK) {
snooze(200000);
port_info info;
int32 cookie = 0;
fStatus = B_ERROR;
while (get_next_port_info(fTeam, &cookie, &info) == B_OK) {
if (!strcmp(info.name, "AppLooperPort")) {
fStatus = B_OK;
port = info.port;
break;
}
}
}
// get a messenger
if (fStatus == B_OK) {
struct {
port_id fPort;
int32 fHandlerToken;
team_id fTeam;
int32 extra0;
int32 extra1;
bool fPreferredTarget;
bool extra2;
bool extra3;
bool extra4;
} fakeMessenger;
fakeMessenger.fPort = port;
fakeMessenger.fHandlerToken = -1;
fakeMessenger.fTeam = fTeam;
fakeMessenger.fPreferredTarget = true;
fMessenger = *(BMessenger*)&fakeMessenger;
if (!fMessenger.IsValid())
fStatus = B_ERROR;
}
}
// set result
if (fStatus == B_OK)
monitor = fMessenger;
fLock.Unlock();
return fStatus;
}
// WatchingRequest
status_t
NodeMonitor::WatchingRequest(const node_ref *node, uint32 flags,
BMessenger target, bool start)
{
BMessenger monitor;
status_t error = GetMessenger(monitor);
// prepare request message
BMessage request;
if (error == B_OK) {
if (start) {
request.what = 'wtch';
request.AddInt32("device", node->device);
request.AddInt64("node", node->node);
request.AddInt32("flags", (int32)flags);
} else {
request.what = 'hctw';
}
request.AddMessenger("target", target);
}
// send request
BMessage reply;
if (error == B_OK)
error = monitor.SendMessage(&request, &reply);
// analyze reply
if (error == B_OK) {
status_t result;
error = reply.FindInt32("result", &result);
if (error == B_OK)
error = result;
}
return error;
}
// watch_node
status_t
watch_node(const node_ref *node, uint32 flags, BMessenger target)
{
status_t error = B_OK;
if (flags == B_STOP_WATCHING)
error = stop_watching(target);
else {
node_ref fakeNode;
if (!node)
node = &fakeNode;
error = gNodeMonitor.WatchingRequest(node, flags, target, true);
}
return error;
}
// watch_node
status_t
watch_node(const node_ref *node, uint32 flags, const BHandler *handler,
const BLooper *looper)
{
status_t error = (handler || looper ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
BMessenger target(handler, looper);
error = watch_node(node, flags, target);
}
return error;
}
// stop_watching
status_t
stop_watching(BMessenger target)
{
return gNodeMonitor.WatchingRequest(NULL, 0, target, false);
}
// stop_watching
status_t
stop_watching(const BHandler *handler, const BLooper *looper)
{
status_t error = (handler || looper ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
BMessenger target(handler, looper);
error = stop_watching(target);
}
return error;
}

View File

@ -1,361 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
#include <errno.h>
#include <fcntl.h>
#include <new.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <disk_scanner.h>
#include "RDiskDevice.h"
#include "RDiskDeviceList.h"
#include "RPartition.h"
#include "RSession.h"
// constructor
RDiskDevice::RDiskDevice()
: fSessions(10, true),
fDeviceList(NULL),
fID(-1),
fChangeCounter(),
fTouched(false),
fPath(),
fFD(-1),
fMediaStatus(B_ERROR)
{
}
// destructor
RDiskDevice::~RDiskDevice()
{
Unset();
}
// SetTo
status_t
RDiskDevice::SetTo(const char *path, int fd, const device_geometry *geometry,
status_t mediaStatus)
{
PRINT(("RDiskDevice::SetTo()\n"));
Unset();
status_t error = B_OK;
fID = _NextID();
fChangeCounter.Reset();
fTouched = true;
fPath.SetTo(path);
fFD = fd;
fGeometry = *geometry;
fMediaStatus = mediaStatus;
// analyze the media status
switch (fMediaStatus) {
case B_NO_ERROR:
case B_DEV_NO_MEDIA:
case B_DEV_NOT_READY:
case B_DEV_MEDIA_CHANGE_REQUESTED:
case B_DEV_DOOR_OPEN:
break;
case B_DEV_MEDIA_CHANGED:
// the user was fast enough to change the media between opening
// and requesting the media status -- media is in, so we are fine
fMediaStatus = B_OK;
break;
default:
error = fMediaStatus;
break;
}
// scan the device for sessions
error = _RescanSessions(B_DEVICE_CAUSE_UNKNOWN);
// cleanup on error
if (error != B_OK)
Unset();
RETURN_ERROR(error);
// return error;
}
// Unset
void
RDiskDevice::Unset()
{
for (int32 i = CountSessions() - 1; i >= 0; i--)
RemoveSession(i, B_DEVICE_CAUSE_UNKNOWN);
fID = -1;
fPath.SetTo("");
if (fFD >= 0) {
close(fFD);
fFD = -1;
}
}
// MediaChanged
status_t
RDiskDevice::MediaChanged()
{
PRINT(("RDiskDevice::MediaChanged()\n"));
Changed();
status_t error = B_OK;
// get the new media status
status_t mediaStatus;
if (ioctl(fFD, B_GET_MEDIA_STATUS, &mediaStatus) == 0) {
fMediaStatus = mediaStatus;
// analyze the media status
switch (fMediaStatus) {
case B_NO_ERROR:
case B_DEV_NO_MEDIA:
case B_DEV_NOT_READY:
case B_DEV_MEDIA_CHANGE_REQUESTED:
case B_DEV_DOOR_OPEN:
break;
case B_DEV_MEDIA_CHANGED:
// Ignore changes between the ioctl() and the one before;
// we rescan the sessions anyway.
fMediaStatus = B_OK;
break;
default:
error = fMediaStatus;
break;
}
}
// get the device geometry
if (ioctl(fFD, B_GET_GEOMETRY, &fGeometry) != 0)
error = errno;
// rescan sessions
if (error == B_OK)
error = _RescanSessions(B_DEVICE_CAUSE_PARENT_CHANGED);
// notification
if (fDeviceList)
fDeviceList->MediaChanged(this, B_DEVICE_CAUSE_MEDIA_CHANGED);
return error;
}
// SessionLayoutChanged
status_t
RDiskDevice::SessionLayoutChanged()
{
PRINT(("RDiskDevice::SessionLayoutChanged()\n"));
Changed();
status_t error = B_OK;
error = _RescanSessions(B_DEVICE_CAUSE_UNKNOWN);
return error;
}
// Size
off_t
RDiskDevice::Size() const
{
return (off_t)fGeometry.bytes_per_sector * fGeometry.sectors_per_track
* fGeometry.cylinder_count * fGeometry.head_count;
}
// AddSession
status_t
RDiskDevice::AddSession(const session_info *sessionInfo, uint32 cause)
{
status_t error = B_OK;
if (RSession *session = new(nothrow) RSession) {
error = session->SetTo(fFD, sessionInfo);
if (error == B_OK)
AddSession(session, cause);
else
delete session;
} else
error = B_NO_MEMORY;
return error;
}
// AddSession
bool
RDiskDevice::AddSession(RSession *session, uint32 cause)
{
bool success = false;
if (session) {
success = fSessions.AddItem(session);
if (success) {
session->SetDevice(this);
Changed();
if (RDiskDeviceList *deviceList = DeviceList())
deviceList->SessionAdded(session, cause);
}
}
return success;
}
// RemoveSession
bool
RDiskDevice::RemoveSession(int32 index, uint32 cause)
{
RSession *session = SessionAt(index);
if (session) {
Changed();
if (RDiskDeviceList *deviceList = DeviceList())
deviceList->SessionRemoved(session, cause);
session->SetDevice(NULL);
fSessions.RemoveItemAt(index);
delete session;
}
return (session != NULL);
}
// RemoveSession
bool
RDiskDevice::RemoveSession(RSession *session, uint32 cause)
{
bool success = false;
if (session) {
int32 index = fSessions.IndexOf(session);
if (index >= 0)
success = RemoveSession(index, cause);
}
return success;
}
// Update
status_t
RDiskDevice::Update()
{
RChangeCounter::Locker lock(fChangeCounter);
status_t error = B_OK;
status_t mediaStatus = B_OK;
if (ioctl(fFD, B_GET_MEDIA_STATUS, &mediaStatus) == 0) {
if (mediaStatus == B_DEV_MEDIA_CHANGED
|| (mediaStatus == B_NO_ERROR) != (fMediaStatus == B_NO_ERROR)) {
// The media status is B_DEV_MEDIA_CHANGED or it changed from
// B_NO_ERROR to some error code or the other way around.
error = MediaChanged();
} else {
// TODO: notifications?
fMediaStatus = mediaStatus;
// The media has not been changed. If this is a read-only device,
// then we are safe, since nothing can have changed. Otherwise
// we check the sessions.
if (!IsReadOnly() && fMediaStatus == B_OK) {
session_info sessionInfo;
for (int32 i = 0; error == B_OK; i++) {
// get the session info
status_t status = get_nth_session_info(fFD, i,
&sessionInfo);
if (status != B_OK) {
if (status == B_ENTRY_NOT_FOUND) {
// remove disappeared sessions
for (int32 k = CountSessions() - 1; k >= i; k--)
RemoveSession(k, B_DEVICE_CAUSE_UNKNOWN);
} else {
// ignore errors -- we can't help it
// error = status;
}
break;
}
// check the session
if (RSession *session = SessionAt(i)) {
if (session->Offset() == sessionInfo.offset
&& session->Size() == sessionInfo.size) {
session->Update(&sessionInfo);
} else {
// session layout changed
error = SessionLayoutChanged();
break;
}
} else {
// session added
error = AddSession(&sessionInfo,
B_DEVICE_CAUSE_UNKNOWN);
}
}
}
}
}
return error;
}
// Archive
status_t
RDiskDevice::Archive(BMessage *archive) const
{
status_t error = (archive ? B_OK : B_BAD_VALUE);
// ID and change counter
if (error == B_OK)
error = archive->AddInt32("id", fID);
if (error == B_OK)
error = archive->AddInt32("change_counter", ChangeCounter());
// geometry
if (error == B_OK)
error = archive->AddInt64("size", Size());
if (error == B_OK)
error = archive->AddInt32("block_size", BlockSize());
if (error == B_OK)
error = archive->AddInt8("type", (int8)fGeometry.device_type);
if (error == B_OK)
error = archive->AddBool("removable", fGeometry.removable);
if (error == B_OK)
error = archive->AddBool("read_only", fGeometry.read_only);
if (error == B_OK)
error = archive->AddBool("write_once", fGeometry.write_once);
// other data
if (error == B_OK)
error = archive->AddString("path", fPath.String());
if (error == B_OK)
error = archive->AddInt32("media_status", fMediaStatus);
// sessions
for (int32 i = 0; const RSession *session = SessionAt(i); i++) {
BMessage sessionArchive;
error = session->Archive(&sessionArchive);
if (error == B_OK)
error = archive->AddMessage("sessions", &sessionArchive);
if (error != B_OK)
break;
}
return error;
}
// Dump
void
RDiskDevice::Dump() const
{
printf("device `%s'\n", Path());
for (int32 i = 0; RSession *session = SessionAt(i); i++)
session->Dump();
}
// _RescanSessions
status_t
RDiskDevice::_RescanSessions(uint32 cause)
{
status_t error = B_OK;
// remove the current sessions
for (int32 i = CountSessions() - 1; i >= 0; i--)
RemoveSession(i, cause);
// scan the device for sessions, if we have a media
if (fMediaStatus == B_OK) {
session_info sessionInfo;
for (int32 i = 0; error == B_OK; i++) {
// get the session info
status_t status = get_nth_session_info(fFD, i, &sessionInfo);
if (status != B_OK) {
if (status != B_ENTRY_NOT_FOUND) {
// ignore errors -- we can't help it
// error = status;
}
break;
}
// create and add a RSession
error = AddSession(&sessionInfo, cause);
}
}
RETURN_ERROR(error);
}
// _NextID
int32
RDiskDevice::_NextID()
{
return atomic_add(&fNextID, 1);
}
// fNextID
vint32 RDiskDevice::fNextID = 0;

View File

@ -1,632 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
#include <fcntl.h>
#include <new.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <Directory.h>
#include <DiskDeviceRoster.h>
#include <Drivers.h>
#include <Entry.h>
#include <Locker.h>
#include <Path.h>
#include "RDiskDeviceList.h"
#include "Debug.h"
#include "EventMaskWatcher.h"
#include "RDiskDevice.h"
#include "RPartition.h"
#include "RSession.h"
#include "WatchingService.h"
namespace RDiskDeviceListPredicates {
// CompareIDPredicate
template <typename T>
struct CompareIDPredicate : public UnaryPredicate<T> {
CompareIDPredicate(int32 id) : fID(id) {}
CompareIDPredicate(const T *object) : fID(object->ID()) {}
virtual int operator()(const T *object) const
{
int32 id = object->ID();
if (fID < id)
return 1;
if (fID > id)
return -1;
return 0;
}
private:
int32 fID;
};
// CompareDevicePathPredicate
struct CompareDevicePathPredicate : public UnaryPredicate<RDiskDevice> {
CompareDevicePathPredicate(const char *path) : fPath(path) {}
virtual int operator()(const RDiskDevice *device) const
{
return strcmp(fPath, device->Path());
}
private:
const char *fPath;
};
// ComparePartitionPathPredicate
struct ComparePartitionPathPredicate : public UnaryPredicate<RPartition> {
ComparePartitionPathPredicate(const char *path) : fPath(path) {}
virtual int operator()(const RPartition *partition) const
{
char path[B_FILE_NAME_LENGTH];
partition->GetPath(path);
return strcmp(fPath, path);
}
private:
const char *fPath;
};
} // namespace RDiskDeviceListPredicates
using namespace RDiskDeviceListPredicates;
// constructor
RDiskDeviceList::RDiskDeviceList(BMessenger target, BLocker &lock,
RVolumeList &volumeList,
WatchingService *watchingService)
: MessageHandler(),
RVolumeListListener(),
fLock(lock),
fTarget(target),
fVolumeList(volumeList),
fWatchingService(watchingService),
fDevices(20, true),
fSessions(40, false),
fPartitions(80, false)
{
fVolumeList.SetListener(this);
}
// destructor
RDiskDeviceList::~RDiskDeviceList()
{
}
// HandleMessage
void
RDiskDeviceList::HandleMessage(BMessage *message)
{
if (Lock()) {
switch (message->what) {
default:
MessageHandler::HandleMessage(message);
break;
}
Unlock();
}
}
// VolumeMounted
void
RDiskDeviceList::VolumeMounted(const RVolume *volume)
{
PRINT(("RDiskDeviceList::VolumeMounted(%ld)\n", volume->ID()));
Lock();
// get the partition and set its volume
const char *devicePath = volume->DevicePath();
if (RPartition *partition = PartitionWithPath(devicePath)) {
partition->SetVolume(volume);
// send notifications
BMessage notification(B_DEVICE_UPDATE);
if (_InitNotificationMessage(&notification,
B_DEVICE_PARTITION_MOUNTED, B_DEVICE_CAUSE_UNKNOWN,
partition) == B_OK) {
EventMaskWatcherFilter filter(B_DEVICE_REQUEST_MOUNTING);
fWatchingService->NotifyWatchers(&notification, &filter);
}
}
Unlock();
}
// VolumeUnmounted
void
RDiskDeviceList::VolumeUnmounted(const RVolume *volume)
{
PRINT(("RDiskDeviceList::VolumeUnmounted(%ld)\n", volume->ID()));
Lock();
// get the partition and set its volume
const char *devicePath = volume->DevicePath();
if (RPartition *partition = PartitionWithPath(devicePath)) {
partition->SetVolume(NULL);
// send notifications
BMessage notification(B_DEVICE_UPDATE);
if (_InitNotificationMessage(&notification,
B_DEVICE_PARTITION_UNMOUNTED, B_DEVICE_CAUSE_UNKNOWN,
partition) == B_OK) {
EventMaskWatcherFilter filter(B_DEVICE_REQUEST_MOUNTING);
fWatchingService->NotifyWatchers(&notification, &filter);
}
}
Unlock();
}
// MountPointMoved
void
RDiskDeviceList::MountPointMoved(const RVolume *volume,
const entry_ref *oldRoot,
const entry_ref *newRoot)
{
PRINT(("RDiskDeviceList::MountPointMoved(%ld)\n", volume->ID()));
Lock();
// get the partition
const char *devicePath = volume->DevicePath();
if (RPartition *partition = PartitionWithPath(devicePath)) {
// send notifications
BMessage notification(B_DEVICE_UPDATE);
if (_InitNotificationMessage(&notification,
B_DEVICE_MOUNT_POINT_MOVED, B_DEVICE_CAUSE_UNKNOWN,
partition) == B_OK
&& notification.AddRef("old_directory", oldRoot) == B_OK
&& notification.AddRef("new_directory", newRoot) == B_OK) {
EventMaskWatcherFilter filter(B_DEVICE_REQUEST_MOUNT_POINT);
fWatchingService->NotifyWatchers(&notification, &filter);
}
}
Unlock();
}
// DeviceAppeared
void
RDiskDeviceList::DeviceAppeared(const char *devicePath)
{
status_t error = (devicePath ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
int fd = open(devicePath, O_RDONLY);
if (fd >= 0) {
bool closeFile = true;
device_geometry geometry;
status_t mediaStatus = B_OK;
partition_info partitionInfo;
if (ioctl(fd, B_GET_MEDIA_STATUS, &mediaStatus) == 0
&& ioctl(fd, B_GET_GEOMETRY, &geometry) == 0
&& ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo) < 0) {
PRINT(("RDiskDeviceList::DeviceAppeared(`%s')\n", devicePath));
RDiskDevice *device = new(nothrow) RDiskDevice;
if (device) {
error = device->SetTo(devicePath, fd, &geometry,
mediaStatus);
if (error == B_OK) {
closeFile = false;
device->SetTouched(true);
AddDevice(device);
} else
delete device;
} else
error = B_NO_MEMORY;
}
if (closeFile)
close(fd);
}
}
}
// DeviceDisappeared
void
RDiskDeviceList::DeviceDisappeared(const char *devicePath)
{
PRINT(("RDiskDeviceList::DeviceDisappeared(`%s')\n", devicePath));
if (devicePath) {
if (RDiskDevice *device = DeviceWithPath(devicePath))
RemoveDevice(device);
}
}
// AddDevice
bool
RDiskDeviceList::AddDevice(RDiskDevice *device)
{
bool success = false;
if (device) {
fDevices.BinaryInsert(device, CompareIDPredicate<RDiskDevice>(device));
device->SetDeviceList(this);
DeviceAdded(device);
}
return success;
}
// RemoveDevice
bool
RDiskDeviceList::RemoveDevice(int32 index)
{
RDiskDevice *device = DeviceAt(index);
if (device) {
DeviceRemoved(device);
device->SetDeviceList(NULL);
fDevices.RemoveItemAt(index);
delete device;
}
return (device != NULL);
}
// RemoveDevice
bool
RDiskDeviceList::RemoveDevice(RDiskDevice *device)
{
bool success = false;
if (device) {
int32 index = fDevices.FindBinaryInsertionIndex(
CompareIDPredicate<RDiskDevice>(device), &success);
if (success)
success = RemoveDevice(index);
}
return success;
}
// DeviceWithID
RDiskDevice *
RDiskDeviceList::DeviceWithID(int32 id, bool exact) const
{
bool inList = false;
int32 index = fDevices.FindBinaryInsertionIndex(
CompareIDPredicate<RDiskDevice>(id), &inList);
return (inList || !exact ? DeviceAt(index) : NULL);
}
// SessionWithID
RSession *
RDiskDeviceList::SessionWithID(int32 id) const
{
bool inList = false;
int32 index = fSessions.FindBinaryInsertionIndex(
CompareIDPredicate<RSession>(id), &inList);
return (inList ? SessionAt(index) : NULL);
}
// PartitionWithID
RPartition *
RDiskDeviceList::PartitionWithID(int32 id) const
{
bool inList = false;
int32 index = fPartitions.FindBinaryInsertionIndex(
CompareIDPredicate<RPartition>(id), &inList);
return (inList ? PartitionAt(index) : NULL);
}
// DeviceWithPath
RDiskDevice *
RDiskDeviceList::DeviceWithPath(const char *path) const
{
const RDiskDevice *device
= fDevices.FindIf(CompareDevicePathPredicate(path));
return const_cast<RDiskDevice*>(device);
}
// PartitionWithPath
RPartition *
RDiskDeviceList::PartitionWithPath(const char *path) const
{
const RPartition *partition
= fPartitions.FindIf(ComparePartitionPathPredicate(path));
return const_cast<RPartition*>(partition);
}
// Rescan
status_t
RDiskDeviceList::Rescan()
{
FUNCTION_START();
// TODO: This method should be reworked, as soon as we react on events only
// and don't need to poll anymore. This method will then do an initial
// scan only.
status_t error = B_OK;
if (Lock()) {
// marked all devices untouched
for (int32 i = 0; RDiskDevice *device = DeviceAt(i); i++)
device->SetTouched(false);
// scan the "/dev/disk" directory for devices
BDirectory dir;
if (dir.SetTo("/dev/disk") == B_OK) {
error = _Scan(dir);
}
// remove all untouched devices
for (int32 i = CountDevices() - 1; i >= 0; i--) {
RDiskDevice *device = DeviceAt(i);
if (!device->Touched())
DeviceDisappeared(device->Path());
}
Unlock();
} else
error = B_ERROR;
FUNCTION_END();
return error;
}
// Lock
bool
RDiskDeviceList::Lock()
{
return fLock.Lock();
}
// Unlock
void
RDiskDeviceList::Unlock()
{
fLock.Unlock();
}
// DeviceAdded
void
RDiskDeviceList::DeviceAdded(RDiskDevice *device, uint32 cause)
{
// propagate to sessions
for (int32 i = 0; RSession *session = device->SessionAt(i); i++)
SessionAdded(session, B_DEVICE_CAUSE_PARENT_CHANGED);
// notifications
BMessage notification(B_DEVICE_UPDATE);
if (_InitNotificationMessage(&notification, B_DEVICE_ADDED,
cause, device) == B_OK) {
EventMaskWatcherFilter filter(B_DEVICE_REQUEST_DEVICE_LIST);
fWatchingService->NotifyWatchers(&notification, &filter);
}
}
// DeviceRemoved
void
RDiskDeviceList::DeviceRemoved(RDiskDevice *device, uint32 cause)
{
// propagate to sessions
for (int32 i = 0; RSession *session = device->SessionAt(i); i++)
SessionRemoved(session, B_DEVICE_CAUSE_PARENT_CHANGED);
// notifications
BMessage notification(B_DEVICE_UPDATE);
if (_InitNotificationMessage(&notification, B_DEVICE_REMOVED,
cause, device) == B_OK) {
EventMaskWatcherFilter filter(B_DEVICE_REQUEST_DEVICE_LIST);
fWatchingService->NotifyWatchers(&notification, &filter);
}
}
// MediaChanged
void
RDiskDeviceList::MediaChanged(RDiskDevice *device, uint32 cause)
{
// notifications
BMessage notification(B_DEVICE_UPDATE);
if (_InitNotificationMessage(&notification, B_DEVICE_MEDIA_CHANGED,
cause, device) == B_OK) {
EventMaskWatcherFilter filter(B_DEVICE_REQUEST_DEVICE);
fWatchingService->NotifyWatchers(&notification, &filter);
}
}
// SessionAdded
void
RDiskDeviceList::SessionAdded(RSession *session, uint32 cause)
{
// add the session to our list
fSessions.BinaryInsert(session, CompareIDPredicate<RSession>(session));
// propagate to partitions
for (int32 i = 0; RPartition *partition = session->PartitionAt(i); i++)
PartitionAdded(partition, B_DEVICE_CAUSE_PARENT_CHANGED);
// notifications
// TODO: bundle multiple session added events per device
if (cause != B_DEVICE_CAUSE_PARENT_CHANGED) {
BMessage notification(B_DEVICE_UPDATE);
if (_InitNotificationMessage(&notification, B_DEVICE_SESSION_ADDED,
cause, session) == B_OK) {
EventMaskWatcherFilter filter(B_DEVICE_REQUEST_DEVICE);
fWatchingService->NotifyWatchers(&notification, &filter);
}
}
}
// SessionRemoved
void
RDiskDeviceList::SessionRemoved(RSession *session, uint32 cause)
{
// remove the session from our list
bool success = false;
int32 index = fSessions.FindBinaryInsertionIndex(
CompareIDPredicate<RSession>(session), &success);
if (success)
fSessions.RemoveItemAt(index);
// propagate to partitions
for (int32 i = 0; RPartition *partition = session->PartitionAt(i); i++)
PartitionRemoved(partition, B_DEVICE_CAUSE_PARENT_CHANGED);
// notifications
// TODO: bundle multiple session removed events per device
if (cause != B_DEVICE_CAUSE_PARENT_CHANGED) {
BMessage notification(B_DEVICE_UPDATE);
if (_InitNotificationMessage(&notification, B_DEVICE_SESSION_REMOVED,
cause, session) == B_OK) {
EventMaskWatcherFilter filter(B_DEVICE_REQUEST_DEVICE);
fWatchingService->NotifyWatchers(&notification, &filter);
}
}
}
// PartitionAdded
void
RDiskDeviceList::PartitionAdded(RPartition *partition, uint32 cause)
{
// add the partition to our list
fPartitions.BinaryInsert(partition,
CompareIDPredicate<RPartition>(partition));
// get the corresponding volume, if partition is mounted
char path[B_FILE_NAME_LENGTH];
partition->GetPath(path);
if (const RVolume *volume = fVolumeList.VolumeForDevicePath(path))
partition->SetVolume(volume);
// notifications
// TODO: bundle multiple partition added events per session
if (cause != B_DEVICE_CAUSE_PARENT_CHANGED) {
BMessage notification(B_DEVICE_UPDATE);
if (_InitNotificationMessage(&notification, B_DEVICE_PARTITION_ADDED,
cause, partition) == B_OK) {
EventMaskWatcherFilter filter(B_DEVICE_REQUEST_SESSION);
fWatchingService->NotifyWatchers(&notification, &filter);
}
}
}
// PartitionRemoved
void
RDiskDeviceList::PartitionRemoved(RPartition *partition, uint32 cause)
{
// remove the partition from our list
bool success = false;
int32 index = fPartitions.FindBinaryInsertionIndex(
CompareIDPredicate<RPartition>(partition), &success);
if (success)
fPartitions.RemoveItemAt(index);
// notifications
// TODO: bundle multiple partition removed events per session
if (cause != B_DEVICE_CAUSE_PARENT_CHANGED) {
BMessage notification(B_DEVICE_UPDATE);
if (_InitNotificationMessage(&notification, B_DEVICE_PARTITION_REMOVED,
cause, partition) == B_OK) {
EventMaskWatcherFilter filter(B_DEVICE_REQUEST_SESSION);
fWatchingService->NotifyWatchers(&notification, &filter);
}
}
}
// PartitionChanged
void
RDiskDeviceList::PartitionChanged(RPartition *partition, uint32 cause)
{
// notifications
if (cause != B_DEVICE_CAUSE_PARENT_CHANGED) {
BMessage notification(B_DEVICE_UPDATE);
if (_InitNotificationMessage(&notification, B_DEVICE_PARTITION_CHANGED,
cause, partition) == B_OK) {
EventMaskWatcherFilter filter(B_DEVICE_REQUEST_PARTITION);
fWatchingService->NotifyWatchers(&notification, &filter);
}
}
}
// Dump
void
RDiskDeviceList::Dump() const
{
for (int32 i = 0; RDiskDevice *device = DeviceAt(i); i++)
device->Dump();
}
// _Scan
status_t
RDiskDeviceList::_Scan(BDirectory &dir)
{
status_t error = B_OK;
BEntry entry;
while (dir.GetNextEntry(&entry) == B_OK) {
struct stat st;
if (entry.GetStat(&st) == B_OK) {
if (S_ISDIR(st.st_mode)) {
BDirectory subdir;
if (subdir.SetTo(&entry) == B_OK)
error = _Scan(subdir);
} else if (!S_ISLNK(st.st_mode)) {
BPath path;
if (entry.GetPath(&path) == B_OK) {
_ScanDevice(path.Path());
}
}
}
}
return error;
}
// _ScanDevice
status_t
RDiskDeviceList::_ScanDevice(const char *path)
{
status_t error = B_OK;
// search the list for a device with that path
if (RDiskDevice *device = DeviceWithPath(path)) {
// found: just update it
device->SetTouched(true);
error = device->Update();
} else {
// not found: check whether it is really a disk device and add it to
// the list
// The event hook does the work anyway:
DeviceAppeared(path);
}
return error;
}
// _InitNotificationMessage
status_t
RDiskDeviceList::_InitNotificationMessage(BMessage *message, uint32 event,
uint32 cause)
{
status_t error = (message ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
message->what = B_DEVICE_UPDATE;
error = message->AddInt32("event", event);
}
if (error == B_OK)
error = message->AddInt32("cause", cause);
return error;
}
// _InitNotificationMessage
status_t
RDiskDeviceList::_InitNotificationMessage(BMessage *message, uint32 event,
uint32 cause,
const RDiskDevice *device)
{
status_t error = (device ? B_OK : B_BAD_VALUE);
if (error == B_OK)
error = _InitNotificationMessage(message, event, cause);
if (error == B_OK)
error = message->AddInt32("device_id", device->ID());
return error;
}
// _InitNotificationMessage
status_t
RDiskDeviceList::_InitNotificationMessage(BMessage *message, uint32 event,
uint32 cause,
const RSession *session)
{
status_t error = (session ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
error = _InitNotificationMessage(message, event, cause,
session->Device());
}
if (error == B_OK)
error = message->AddInt32("session_id", session->ID());
return error;
}
// _InitNotificationMessage
status_t
RDiskDeviceList::_InitNotificationMessage(BMessage *message, uint32 event,
uint32 cause,
const RPartition *partition)
{
status_t error = (partition ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
error = _InitNotificationMessage(message, event, cause,
partition->Session());
}
if (error == B_OK)
error = message->AddInt32("partition_id", partition->ID());
return error;
}

View File

@ -1,207 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
#include "RPartition.h"
#include "RDiskDevice.h"
#include "RDiskDeviceList.h"
#include "RSession.h"
// constructor
RPartition::RPartition()
: fSession(NULL),
fID(-1),
fChangeCounter(),
fVolume(NULL)
{
}
// destructor
RPartition::~RPartition()
{
}
// SetTo
status_t
RPartition::SetTo(int fd, const extended_partition_info *partitionInfo)
{
Unset();
status_t error = B_OK;
fID = _NextID();
fChangeCounter.Reset();
fInfo = *partitionInfo;
return error;
}
// Unset
void
RPartition::Unset()
{
fID = -1;
}
// PartitionChanged
status_t
RPartition::PartitionChanged()
{
Changed();
status_t error = B_OK;
// notification
if (RDiskDeviceList *deviceList = DeviceList())
deviceList->PartitionChanged(this, B_DEVICE_CAUSE_UNKNOWN);
return error;
}
// DeviceList
RDiskDeviceList *
RPartition::DeviceList() const
{
return (fSession ? fSession->DeviceList() : NULL);
}
// Device
RDiskDevice *
RPartition::Device() const
{
return (fSession ? fSession->Device() : NULL);
}
// Changed
void
RPartition::Changed()
{
if (fChangeCounter.Increment() && fSession)
fSession->Changed();
}
// Index
int32
RPartition::Index() const
{
if (fSession)
return fSession->IndexOfPartition(this);
return -1;
}
// GetPath
void
RPartition::GetPath(char *path) const
{
RDiskDevice *device = Device();
if (path && device) {
strcpy(path, device->Path());
if (char *lastSlash = strrchr(path, '/'))
sprintf(lastSlash + 1, "%ld_%ld", Session()->Index(), Index());
}
}
// Update
status_t
RPartition::Update(const extended_partition_info *partitionInfo)
{
RChangeCounter::Locker lock(fChangeCounter);
status_t error = B_OK;
// check the partition info for changes
// Currently there is very little that can have changed. offset and size
// must not be changed, logical_block_size and device are ignored anyway
// and session and partition index don't change.
// So only the fields in extended_partition_info - partition_info remain.
if (partitionInfo->flags != fInfo.flags
|| strcmp(partitionInfo->partition_name, fInfo.partition_name)
|| strcmp(partitionInfo->partition_type, fInfo.partition_type)
|| strcmp(partitionInfo->file_system_short_name,
fInfo.file_system_short_name)
|| strcmp(partitionInfo->file_system_short_name,
fInfo.file_system_short_name)
|| strcmp(partitionInfo->file_system_long_name,
fInfo.file_system_long_name)
|| strcmp(partitionInfo->volume_name, fInfo.volume_name)
|| partitionInfo->file_system_flags != fInfo.file_system_flags) {
fInfo = *partitionInfo;
PartitionChanged();
}
return error;
}
// Archive
status_t
RPartition::Archive(BMessage *archive) const
{
status_t error = (archive ? B_OK : B_BAD_VALUE);
// ID, change counter and index
if (error == B_OK)
error = archive->AddInt32("id", fID);
if (error == B_OK)
error = archive->AddInt32("change_counter", ChangeCounter());
if (error == B_OK)
error = archive->AddInt32("index", Index());
// fInfo.info.*
if (error == B_OK)
error = archive->AddInt64("offset", fInfo.info.offset);
if (error == B_OK)
error = archive->AddInt64("size", fInfo.info.size);
// fInfo.*
if (error == B_OK)
error = archive->AddInt32("flags", (int32)fInfo.flags);
if (error == B_OK)
error = archive->AddString("name", fInfo.partition_name);
if (error == B_OK)
error = archive->AddString("type", fInfo.partition_type);
if (error == B_OK) {
error = archive->AddString("fs_short_name",
fInfo.file_system_short_name);
}
if (error == B_OK) {
error = archive->AddString("fs_long_name",
fInfo.file_system_long_name);
}
if (error == B_OK)
error = archive->AddString("volume_name", fInfo.volume_name);
if (error == B_OK)
error = archive->AddInt32("fs_flags", (int32)fInfo.file_system_flags);
// dev_t, if mounted
if (error == B_OK && fVolume)
error = archive->AddInt32("volume_id", fVolume->ID());
return error;
}
// print_partition_info
static
void
print_partition_info(const char *prefix, const extended_partition_info &info)
{
printf("%soffset: %lld\n", prefix, info.info.offset);
printf("%ssize: %lld\n", prefix, info.info.size);
printf("%sblock size: %ld\n", prefix, info.info.logical_block_size);
printf("%ssession ID: %ld\n", prefix, info.info.session);
printf("%spartition ID: %ld\n", prefix, info.info.partition);
printf("%sdevice: `%s'\n", prefix, info.info.device);
printf("%sflags: %lx\n", prefix, info.flags);
printf("%spartition name: `%s'\n", prefix, info.partition_name);
printf("%spartition type: `%s'\n", prefix, info.partition_type);
printf("%sFS short name: `%s'\n", prefix, info.file_system_short_name);
printf("%sFS long name: `%s'\n", prefix, info.file_system_long_name);
printf("%svolume name: `%s'\n", prefix, info.volume_name);
// printf("%smounted at: `%s'\n", prefix, info.mounted_at);
printf("%sFS flags: 0x%lx\n", prefix, info.file_system_flags);
}
// Dump
void
RPartition::Dump() const
{
printf(" partition %ld:\n", fInfo.info.partition);
print_partition_info(" ", fInfo);
}
// _NextID
int32
RPartition::_NextID()
{
return atomic_add(&fNextID, 1);
}
// fNextID
vint32 RPartition::fNextID = 0;

View File

@ -1,305 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
#include <new.h>
#include <Drivers.h>
#include "RSession.h"
#include "RDiskDevice.h"
#include "RDiskDeviceList.h"
#include "RPartition.h"
// constructor
RSession::RSession()
: fPartitions(10, true),
fDevice(NULL),
fID(-1),
fChangeCounter()
{
}
// destructor
RSession::~RSession()
{
}
// SetTo
status_t
RSession::SetTo(int fd, const session_info *sessionInfo)
{
Unset();
status_t error = B_OK;
fID = _NextID();
fChangeCounter.Reset();
fInfo = *sessionInfo;
// scan for partitions
error = _RescanPartitions(fd, B_DEVICE_CAUSE_UNKNOWN);
// cleanup on error
if (error != B_OK)
Unset();
return error;
}
// Unset
void
RSession::Unset()
{
for (int32 i = CountPartitions() - 1; i >= 0; i--)
RemovePartition(i, B_DEVICE_CAUSE_UNKNOWN);
fID = -1;
}
// DeviceList
RDiskDeviceList *
RSession::DeviceList() const
{
return (fDevice ? fDevice->DeviceList() : NULL);
}
// PartitionLayoutChanged
status_t
RSession::PartitionLayoutChanged()
{
PRINT(("RSession::PartitionLayoutChanged()\n"));
Changed();
status_t error = (fDevice ? B_OK : B_ERROR);
if (error == B_OK)
error = _RescanPartitions(fDevice->FD(), B_DEVICE_CAUSE_UNKNOWN);
return error;
}
// Changed
void
RSession::Changed()
{
if (fChangeCounter.Increment() && fDevice)
fDevice->Changed();
}
// Index
int32
RSession::Index() const
{
if (fDevice)
return fDevice->IndexOfSession(this);
return -1;
}
// AddPartition
status_t
RSession::AddPartition(int fd, const extended_partition_info *partitionInfo,
uint32 cause)
{
status_t error = B_OK;
if (RPartition *partition = new(nothrow) RPartition) {
error = partition->SetTo(fd, partitionInfo);
if (error == B_OK)
AddPartition(partition, cause);
else
delete partition;
} else
error = B_NO_MEMORY;
return error;
}
// AddPartition
bool
RSession::AddPartition(RPartition *partition, uint32 cause)
{
bool success = false;
if (partition) {
success = fPartitions.AddItem(partition);
if (success) {
partition->SetSession(this);
Changed();
// trigger notifications
if (RDiskDeviceList *deviceList = DeviceList())
deviceList->PartitionAdded(partition, cause);
}
}
return success;
}
// RemovePartition
bool
RSession::RemovePartition(int32 index, uint32 cause)
{
RPartition *partition = PartitionAt(index);
if (partition) {
Changed();
if (RDiskDeviceList *deviceList = DeviceList())
deviceList->PartitionRemoved(partition, cause);
partition->SetSession(NULL);
fPartitions.RemoveItemAt(index);
delete partition;
}
return (partition != NULL);
}
// RemovePartition
bool
RSession::RemovePartition(RPartition *partition, uint32 cause)
{
bool success = false;
if (partition) {
int32 index = fPartitions.IndexOf(partition);
if (index >= 0)
success = RemovePartition(index, cause);
}
return success;
}
// Update
status_t
RSession::Update(const session_info *sessionInfo)
{
RChangeCounter::Locker lock(fChangeCounter);
status_t error = (fDevice ? B_OK : B_ERROR);
// check the session info for changes
// Currently there is very little that can have changed. offset and size
// must not be changed, logical_block_size is ignored anyway and index
// doesn't change. So only flags remains, but that indicates only, if the
// session is virtual or a data/audio partition. So we don't do anything
// for now.
fInfo = *sessionInfo;
int fd = (fDevice ? fDevice->FD() : -1);
// check the partitions
for (int32 i = 0; error == B_OK; i++) {
// get the partition info
extended_partition_info partitionInfo;
char partitioningSystem[B_FILE_NAME_LENGTH];
status_t status = get_nth_partition_info(fd, sessionInfo->index, i,
&partitionInfo, (i == 0 ? partitioningSystem : NULL));
// check the partitioning system
if ((status == B_OK || status == B_ENTRY_NOT_FOUND) && i == 0
&& strcmp(partitioningSystem, fPartitioningSystem)) {
// partitioning system has changed
error = PartitionLayoutChanged();
break;
}
if (status != B_OK) {
if (status == B_ENTRY_NOT_FOUND) {
// remove disappeared partitions
for (int32 k = CountPartitions() - 1; k >= i; k--)
RemovePartition(k, B_DEVICE_CAUSE_UNKNOWN);
} else {
// ignore errors -- we can't help it
// error = status;
}
break;
}
// check the partition
if (RPartition *partition = PartitionAt(i)) {
if (partition->Offset() == partitionInfo.info.offset
&& partition->Size() == partitionInfo.info.size) {
partition->Update(&partitionInfo);
} else {
// partition layout changed
error = PartitionLayoutChanged();
break;
}
} else {
// partition added
error = AddPartition(fd, &partitionInfo, B_DEVICE_CAUSE_UNKNOWN);
}
}
return error;
}
// Archive
status_t
RSession::Archive(BMessage *archive) const
{
status_t error = (archive ? B_OK : B_BAD_VALUE);
// ID, change counter and index
if (error == B_OK)
error = archive->AddInt32("id", fID);
if (error == B_OK)
error = archive->AddInt32("change_counter", ChangeCounter());
if (error == B_OK)
error = archive->AddInt32("index", Index());
// fInfo.*
if (error == B_OK)
error = archive->AddInt64("offset", fInfo.offset);
if (error == B_OK)
error = archive->AddInt64("size", fInfo.size);
if (error == B_OK)
error = archive->AddInt32("flags", (int32)fInfo.flags);
// other data
if (error == B_OK)
error = archive->AddString("partitioning", fPartitioningSystem);
// partitions
for (int32 i = 0; const RPartition *partition = PartitionAt(i); i++) {
BMessage partitionArchive;
error = partition->Archive(&partitionArchive);
if (error == B_OK)
error = archive->AddMessage("partitions", &partitionArchive);
if (error != B_OK)
break;
}
return error;
}
// print_session_info
static
void
print_session_info(const char *prefix, const session_info &info)
{
printf("%soffset: %lld\n", prefix, info.offset);
printf("%ssize: %lld\n", prefix, info.size);
printf("%sblock size: %ld\n", prefix, info.logical_block_size);
printf("%sindex: %ld\n", prefix, info.index);
printf("%sflags: %lx\n", prefix, info.flags);
}
// Dump
void
RSession::Dump() const
{
printf(" session %ld:\n", fInfo.index);
print_session_info(" ", fInfo);
printf(" partitioning : `%s'\n", fPartitioningSystem);
for (int32 i = 0; RPartition *partition = PartitionAt(i); i++)
partition->Dump();
}
// _RescanPartitions
status_t
RSession::_RescanPartitions(int fd, uint32 cause)
{
status_t error = B_OK;
// remove the current partitions
for (int32 i = CountPartitions() - 1; i >= 0; i--)
RemovePartition(i, cause);
// scan for partitions
for (int32 i = 0; error == B_OK; i++) {
// get the partition info
extended_partition_info partitionInfo;
status_t status = get_nth_partition_info(fd, fInfo.index, i,
&partitionInfo, (i == 0 ? fPartitioningSystem : NULL));
if (status != B_OK) {
if (status != B_ENTRY_NOT_FOUND) {
// ignore errors -- we can't help it
// error = status;
}
break;
}
// create and add a RPartition
error = AddPartition(fd, &partitionInfo, cause);
}
return error;
}
// _NextID
int32
RSession::_NextID()
{
return atomic_add(&fNextID, 1);
}
// fNextID
vint32 RSession::fNextID = 0;

View File

@ -1,385 +0,0 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
#include <string.h>
#include <Directory.h>
#include <Entry.h>
#include <Locker.h>
#include <Message.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <Volume.h>
#include "RVolumeList.h"
#include "Debug.h"
namespace RVolumeListPredicates {
// CompareIDPredicate
struct CompareIDPredicate : public UnaryPredicate<RVolume> {
CompareIDPredicate(dev_t id) : fID(id) {}
CompareIDPredicate(const RVolume *volume) : fID(volume->ID()) {}
virtual int operator()(const RVolume *volume) const
{
dev_t id = volume->ID();
if (fID < id)
return 1;
if (fID > id)
return -1;
return 0;
}
private:
dev_t fID;
};
// CompareDevicePathPredicate
struct CompareDevicePathPredicate : public UnaryPredicate<RVolume> {
CompareDevicePathPredicate(const char *path) : fPath(path) {}
virtual int operator()(const RVolume *volume) const
{
return strcmp(fPath, volume->DevicePath());
}
private:
const char *fPath;
};
} // namespace RVolumeListPredicates
using namespace RVolumeListPredicates;
// RVolume
// constructor
RVolume::RVolume()
: fID(-1),
fRootNode(-1),
fRootEntry()
{
}
// SetTo
status_t
RVolume::SetTo(dev_t id)
{
status_t error = B_OK;
// get general info
fs_info info;
error = fs_stat_dev(id, &info);
if (error == B_OK) {
fID = id;
fRootNode = info.root;
if (info.device_name[0] != '\0')
strcpy(fDevicePath, info.device_name);
else // generate a pseudo name -- needed for the list
sprintf(fDevicePath, "%ld", id);
}
// get root dir entry_ref
if (error == B_OK) {
node_ref ref;
GetRootDirNode(&ref);
BDirectory dir;
error = dir.SetTo(&ref);
BEntry entry;
if (error == B_OK)
error = dir.GetEntry(&entry);
if (error == B_OK)
error = entry.GetRef(&fRootEntry);
}
// cleanup on error
if (error != B_OK)
Unset();
return error;
}
// Unset
void
RVolume::Unset()
{
fID = -1;
fRootNode = -1;
}
// StartWatching
status_t
RVolume::StartWatching(BMessenger target) const
{
node_ref ref;
ref.device = fID;
ref.node = fRootNode;
return watch_node(&ref, B_WATCH_NAME, target);
}
// StopWatching
status_t
RVolume::StopWatching(BMessenger target) const
{
node_ref ref;
ref.device = fID;
ref.node = fRootNode;
return watch_node(&ref, B_STOP_WATCHING, target);
}
// RVolumeListListener
// constructor
RVolumeListListener::RVolumeListListener()
{
}
// destructor
RVolumeListListener::~RVolumeListListener()
{
}
// VolumeMounted
void
RVolumeListListener::VolumeMounted(const RVolume *volume)
{
}
// VolumeUnmounted
void
RVolumeListListener::VolumeUnmounted(const RVolume *volume)
{
}
// MountPointMoved
void
RVolumeListListener::MountPointMoved(const RVolume *volume,
const entry_ref *oldRoot,
const entry_ref *newRoot)
{
}
// RVolumeList
// constructor
RVolumeList::RVolumeList(BMessenger target, BLocker &lock)
: MessageHandler(),
fLock(lock),
fTarget(target),
fVolumes(20, true),
fRoster(),
fListener(NULL)
{
// TODO: Remove work-around. At this time R5 libbe's watching functions don't
// work for us. We have an own implementation in `NodeMonitoring.cpp'.
// fRoster.StartWatching(BMessenger(this));
watch_node(NULL, B_WATCH_MOUNT, fTarget);
Rescan();
}
// destructor
RVolumeList::~RVolumeList()
{
// TODO: Remove work-around. At this time R5 libbe's watching functions don't
// work for us. We have an own implementation in `NodeMonitoring.cpp'.
// fRoster.StopWatching();
stop_watching(fTarget);
}
// HandleMessage
void
RVolumeList::HandleMessage(BMessage *message)
{
if (Lock()) {
switch (message->what) {
case B_NODE_MONITOR:
{
int32 opcode = 0;
if (message->FindInt32("opcode", &opcode) == B_OK) {
switch (opcode) {
case B_DEVICE_MOUNTED:
_DeviceMounted(message);
break;
case B_DEVICE_UNMOUNTED:
_DeviceUnmounted(message);
break;
case B_ENTRY_MOVED:
_MountPointMoved(message);
break;
}
}
break;
}
default:
MessageHandler::HandleMessage(message);
break;
}
Unlock();
}
}
// Rescan
status_t
RVolumeList::Rescan()
{
PRINT(("RVolumeList::Rescan()\n"));
for (int32 i = fVolumes.CountItems() - 1; i >= 0; i--)
_RemoveVolumeAt(i);
fRoster.Rewind();
BVolume bVolume;
while (fRoster.GetNextVolume(&bVolume) == B_OK)
_AddVolume(bVolume.Device());
PRINT(("RVolumeList::Rescan() done\n"));
return B_OK;
}
// VolumeForDevicePath
const RVolume *
RVolumeList::VolumeForDevicePath(const char *devicePath) const
{
const RVolume *volume = NULL;
if (devicePath && fLock.Lock()) {
bool found = false;
int32 index = fVolumes.FindBinaryInsertionIndex(
CompareDevicePathPredicate(devicePath), &found);
if (found)
volume = fVolumes.ItemAt(index);
fLock.Unlock();
}
return volume;
}
// Lock
bool
RVolumeList::Lock()
{
return fLock.Lock();
}
// Unlock
void
RVolumeList::Unlock()
{
fLock.Unlock();
}
// SetListener
void
RVolumeList::SetListener(RVolumeListListener *listener)
{
fListener = listener;
}
// Dump
void
RVolumeList::Dump() const
{
for (int32 i = 0; RVolume *volume = fVolumes.ItemAt(i); i++) {
printf("volume %ld:\n", volume->ID());
printf(" root node: %lld", volume->RootNode());
printf(" device: `%s'\n", volume->DevicePath());
}
}
// _AddVolume
RVolume *
RVolumeList::_AddVolume(dev_t id)
{
RVolume *volume = new RVolume;
if (volume) {
status_t error = volume->SetTo(id);
if (error == B_OK) {
fVolumes.BinaryInsert(volume,
CompareDevicePathPredicate(volume->DevicePath()));
volume->StartWatching(fTarget);
} else {
delete volume;
volume = NULL;
PRINT(("RVolumeList::_AddVolume(): initializing RVolume failed: "
"%s\n", strerror(error)));
}
} else
PRINT(("RVolumeList::_AddVolume(): no memory!\n"));
return volume;
}
// _RemoveVolumeAt
bool
RVolumeList::_RemoveVolumeAt(int32 index)
{
bool result = false;
if (RVolume *volume = fVolumes.RemoveItemAt(index)) {
volume->StopWatching(fTarget);
delete volume;
}
return result;
}
// _DeviceMounted
void
RVolumeList::_DeviceMounted(BMessage *message)
{
dev_t device;
if (message->FindInt32("new device", &device) == B_OK) {
PRINT(("RVolumeList::_DeviceMounted(%ld)\n", device));
if (RVolume *volume = _AddVolume(device)) {
if (fListener)
fListener->VolumeMounted(volume);
}
}
}
// _DeviceUnmounted
void
RVolumeList::_DeviceUnmounted(BMessage *message)
{
dev_t device;
if (message->FindInt32("device", &device) == B_OK) {
PRINT(("RVolumeList::_DeviceUnmounted(%ld)\n", device));
if (RVolume *volume = fVolumes.FindIf(CompareIDPredicate(device))) {
volume->StopWatching(fTarget);
fVolumes.RemoveItem(volume, false);
if (fListener)
fListener->VolumeUnmounted(volume);
delete volume;
}
}
}
// _MountPointMoved
void
RVolumeList::_MountPointMoved(BMessage *message)
{
// Note: The "device" field of the message refers to the device of the
// parent directory. Therefore we need to get an entry_ref, turn it into
// a path and get the device for that path.
// get the message fields
dev_t device;
ino_t directory;
const char *name;
if (message->FindInt32("device", &device) == B_OK
&& message->FindInt64("to directory", &directory) == B_OK
&& message->FindString("name", &name) == B_OK) {
// init an entry_ref
entry_ref ref;
ref.device = device;
ref.directory = directory;
ref.set_name(name);
// get the path and the device for that path
BPath path;
if (path.SetTo(&ref) == B_OK
&& (device = dev_for_path(path.Path())) >= 0) {
PRINT(("RVolumeList::_MountPointMoved(%ld)\n", device));
if (RVolume *volume = fVolumes.FindIf(CompareIDPredicate(device))) {
entry_ref oldRoot;
volume->GetRootDirEntry(&oldRoot);
volume->SetRootDirEntry(&ref);
if (fListener)
fListener->MountPointMoved(volume, &oldRoot, &ref);
}
}
}
}

View File

@ -9,7 +9,6 @@
#include <RosterPrivate.h>
#include "ClipboardHandler.h"
#include "DiskDeviceManager.h"
#include "EventQueue.h"
#include "MessageEvent.h"
#include "MessageRunnerManager.h"
@ -38,7 +37,6 @@ Registrar::Registrar()
fRoster(NULL),
fClipboardHandler(NULL),
fMIMEManager(NULL),
fDiskDeviceManager(NULL),
fEventQueue(NULL),
fMessageRunnerManager(NULL),
fSanityEvent(NULL)
@ -60,8 +58,6 @@ Registrar::~Registrar()
delete fMessageRunnerManager;
delete fEventQueue;
delete fSanityEvent;
fDiskDeviceManager->Lock();
fDiskDeviceManager->Quit();
fMIMEManager->Lock();
fMIMEManager->Quit();
RemoveHandler(fClipboardHandler);
@ -102,15 +98,6 @@ Registrar::MessageReceived(BMessage *message)
message->SendReply(&reply);
break;
}
case B_REG_GET_DISK_DEVICE_MESSENGER:
{
PRINT(("B_REG_GET_DISK_DEVICE_MESSENGER\n"));
BMessenger messenger(NULL, fDiskDeviceManager);
BMessage reply(B_REG_SUCCESS);
reply.AddMessenger("messenger", messenger);
message->SendReply(&reply);
break;
}
// roster requests
case B_REG_ADD_APP:
fRoster->HandleAddApplication(message);
@ -229,9 +216,6 @@ Registrar::ReadyToRun()
// create MIME manager
fMIMEManager = new MIMEManager;
fMIMEManager->Run();
// create disk device manager
fDiskDeviceManager = new DiskDeviceManager(fEventQueue);
fDiskDeviceManager->Run();
// create message runner manager
fMessageRunnerManager = new MessageRunnerManager(fEventQueue);
// init the global be_roster

View File

@ -56,7 +56,6 @@ private:
BPrivate::TRoster *fRoster;
ClipboardHandler *fClipboardHandler;
MIMEManager *fMIMEManager;
DiskDeviceManager *fDiskDeviceManager;
EventQueue *fEventQueue;
MessageRunnerManager *fMessageRunnerManager;
MessageEvent *fSanityEvent;

View File

@ -29,6 +29,7 @@
#include <Application.h>
#include <AppMisc.h>
#include <File.h>
#include <storage_support.h>
#include <errno.h>