* Moved Array.h to new directory "types".
* Added StringUtils with string hash functions.
* Added Locatable{Entry,File,Directory} and FileManager classes to manage the
mapping from debug info/target file names to local file names.
* Image does now have a LocatableFile referring to the image's shared object
file. Added listening to location changes of these files to TeamDebugger. No
action is taken yet (should trigger reloading the debug info).
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31368 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -11,9 +11,11 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) arch x86 ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_info ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) elf ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) files ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) gui team_window ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) model ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) types ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) util ] ;
|
||||
|
||||
local debugAnalyzerSources
|
||||
= [ FDirName $(HAIKU_TOP) src apps debuganalyzer ] ;
|
||||
@@ -68,6 +70,12 @@ Application Debugger :
|
||||
# elf
|
||||
ElfFile.cpp
|
||||
|
||||
# files
|
||||
FileManager.cpp
|
||||
LocatableDirectory.cpp
|
||||
LocatableEntry.cpp
|
||||
LocatableFile.cpp
|
||||
|
||||
# gui/team_window
|
||||
ImageFunctionsView.cpp
|
||||
ImageListView.cpp
|
||||
@@ -96,6 +104,9 @@ Application Debugger :
|
||||
# types
|
||||
TargetAddressRangeList.cpp
|
||||
|
||||
# util
|
||||
StringUtils.cpp
|
||||
|
||||
:
|
||||
<nogrist>Debugger_demangler.o
|
||||
<nogrist>Debugger_disasm_x86.o
|
||||
|
||||
@@ -253,7 +253,7 @@ LoadImageDebugInfoJob::Do()
|
||||
// create the debug info
|
||||
ImageDebugInfo* debugInfo;
|
||||
status_t error = fImage->GetTeam()->DebugInfo()->LoadImageDebugInfo(
|
||||
imageInfo, debugInfo);
|
||||
imageInfo, fImage->ImageFile(), debugInfo);
|
||||
|
||||
// set the result
|
||||
locker.Lock();
|
||||
|
||||
@@ -19,6 +19,7 @@ enum {
|
||||
MSG_THREAD_CPU_STATE_CHANGED = 'tcsc',
|
||||
MSG_THREAD_STACK_TRACE_CHANGED = 'tstc',
|
||||
MSG_IMAGE_DEBUG_INFO_CHANGED = 'idic',
|
||||
MSG_IMAGE_FILE_CHANGED = 'ifch',
|
||||
MSG_FUNCTION_SOURCE_CODE_CHANGED = 'fnsc',
|
||||
MSG_USER_BREAKPOINT_CHANGED = 'ubrc',
|
||||
MSG_DEBUGGER_EVENT = 'dbge',
|
||||
|
||||
@@ -20,12 +20,93 @@
|
||||
#include "BreakpointManager.h"
|
||||
#include "CpuState.h"
|
||||
#include "DebuggerInterface.h"
|
||||
#include "FileManager.h"
|
||||
#include "Jobs.h"
|
||||
#include "LocatableFile.h"
|
||||
#include "MessageCodes.h"
|
||||
#include "Statement.h"
|
||||
#include "TeamDebugInfo.h"
|
||||
#include "TeamDebugModel.h"
|
||||
|
||||
// #pragma mark - ImageHandler
|
||||
|
||||
|
||||
struct TeamDebugger::ImageHandler : public Referenceable,
|
||||
public HashTableLink<ImageHandler>, private LocatableFile::Listener {
|
||||
public:
|
||||
ImageHandler(TeamDebugger* teamDebugger, Image* image)
|
||||
:
|
||||
fTeamDebugger(teamDebugger),
|
||||
fImage(image)
|
||||
{
|
||||
fImage->AcquireReference();
|
||||
if (fImage->ImageFile() != NULL)
|
||||
fImage->ImageFile()->AddListener(this);
|
||||
}
|
||||
|
||||
~ImageHandler()
|
||||
{
|
||||
if (fImage->ImageFile() != NULL)
|
||||
fImage->ImageFile()->RemoveListener(this);
|
||||
fImage->ReleaseReference();
|
||||
}
|
||||
|
||||
Image* GetImage() const
|
||||
{
|
||||
return fImage;
|
||||
}
|
||||
|
||||
image_id ImageID() const
|
||||
{
|
||||
return fImage->ID();
|
||||
}
|
||||
|
||||
private:
|
||||
// LocatableFile::Listener
|
||||
virtual void LocatableFileChanged(LocatableFile* file)
|
||||
{
|
||||
BMessage message(MSG_IMAGE_FILE_CHANGED);
|
||||
message.AddInt32("image", fImage->ID());
|
||||
fTeamDebugger->PostMessage(&message);
|
||||
}
|
||||
|
||||
private:
|
||||
TeamDebugger* fTeamDebugger;
|
||||
Image* fImage;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - ImageHandlerHashDefinition
|
||||
|
||||
|
||||
struct TeamDebugger::ImageHandlerHashDefinition {
|
||||
typedef image_id KeyType;
|
||||
typedef ImageHandler ValueType;
|
||||
|
||||
size_t HashKey(image_id key) const
|
||||
{
|
||||
return (size_t)key;
|
||||
}
|
||||
|
||||
size_t Hash(const ImageHandler* value) const
|
||||
{
|
||||
return HashKey(value->ImageID());
|
||||
}
|
||||
|
||||
bool Compare(image_id key, const ImageHandler* value) const
|
||||
{
|
||||
return value->ImageID() == key;
|
||||
}
|
||||
|
||||
HashTableLink<ImageHandler>* GetLink(ImageHandler* value) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - TeamDebugger
|
||||
|
||||
|
||||
TeamDebugger::TeamDebugger(Listener* listener)
|
||||
:
|
||||
@@ -34,7 +115,9 @@ TeamDebugger::TeamDebugger(Listener* listener)
|
||||
fTeam(NULL),
|
||||
fDebugModel(NULL),
|
||||
fTeamID(-1),
|
||||
fImageHandlers(NULL),
|
||||
fDebuggerInterface(NULL),
|
||||
fFileManager(NULL),
|
||||
fWorker(NULL),
|
||||
fBreakpointManager(NULL),
|
||||
fDebugEventListener(-1),
|
||||
@@ -73,15 +156,25 @@ TeamDebugger::~TeamDebugger()
|
||||
ThreadHandler* threadHandler = fThreadHandlers.Clear(true);
|
||||
while (threadHandler != NULL) {
|
||||
ThreadHandler* next = threadHandler->fNext;
|
||||
threadHandler->RemoveReference();
|
||||
threadHandler->ReleaseReference();
|
||||
threadHandler = next;
|
||||
}
|
||||
|
||||
ImageHandler* imageHandler = fImageHandlers->Clear(true);
|
||||
while (imageHandler != NULL) {
|
||||
ImageHandler* next = imageHandler->fNext;
|
||||
imageHandler->ReleaseReference();
|
||||
imageHandler = next;
|
||||
}
|
||||
|
||||
delete fImageHandlers;
|
||||
|
||||
delete fBreakpointManager;
|
||||
delete fDebuggerInterface;
|
||||
delete fWorker;
|
||||
delete fDebugModel;
|
||||
delete fTeam;
|
||||
delete fFileManager;
|
||||
|
||||
fListener->TeamDebuggerQuit(this);
|
||||
}
|
||||
@@ -90,6 +183,9 @@ TeamDebugger::~TeamDebugger()
|
||||
status_t
|
||||
TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
|
||||
{
|
||||
bool targetIsLocal = true;
|
||||
// TODO: Support non-local targets!
|
||||
|
||||
fTeamID = teamID;
|
||||
|
||||
// create debugger interface
|
||||
@@ -101,6 +197,15 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create file manager
|
||||
fFileManager = new(std::nothrow) FileManager;
|
||||
if (fFileManager == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
error = fFileManager->Init(targetIsLocal);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create team debug info
|
||||
TeamDebugInfo* teamDebugInfo = new(std::nothrow) TeamDebugInfo(
|
||||
fDebuggerInterface, fDebuggerInterface->GetArchitecture());
|
||||
@@ -137,6 +242,15 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create image handler table
|
||||
fImageHandlers = new(std::nothrow) ImageHandlerTable;
|
||||
if (fImageHandlers == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
error = fImageHandlers->Init();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create our worker
|
||||
fWorker = new(std::nothrow) Worker;
|
||||
if (fWorker == NULL)
|
||||
@@ -198,7 +312,7 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
|
||||
BObjectList<ImageInfo> imageInfos(20, true);
|
||||
status_t error = fDebuggerInterface->GetImageInfos(imageInfos);
|
||||
for (int32 i = 0; ImageInfo* info = imageInfos.ItemAt(i); i++) {
|
||||
error = fTeam->AddImage(*info);
|
||||
error = _AddImage(*info);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
@@ -320,6 +434,16 @@ TeamDebugger::MessageReceived(BMessage* message)
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_IMAGE_FILE_CHANGED:
|
||||
{
|
||||
int32 imageID;
|
||||
if (message->FindInt32("image", &imageID) != B_OK)
|
||||
break;
|
||||
|
||||
_HandleImageFileChanged(imageID);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_DEBUGGER_EVENT:
|
||||
{
|
||||
DebugEvent* event;
|
||||
@@ -663,7 +787,7 @@ bool
|
||||
TeamDebugger::_HandleImageCreated(ImageCreatedEvent* event)
|
||||
{
|
||||
AutoLocker< ::Team> locker(fTeam);
|
||||
fTeam->AddImage(event->GetImageInfo());
|
||||
_AddImage(event->GetImageInfo());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -673,10 +797,26 @@ TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event)
|
||||
{
|
||||
AutoLocker< ::Team> locker(fTeam);
|
||||
fTeam->RemoveImage(event->GetImageInfo().ImageID());
|
||||
|
||||
ImageHandler* imageHandler = fImageHandlers->Lookup(
|
||||
event->GetImageInfo().ImageID());
|
||||
if (imageHandler != NULL) {
|
||||
fImageHandlers->Remove(imageHandler);
|
||||
imageHandler->ReleaseReference();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::_HandleImageFileChanged(image_id imageID)
|
||||
{
|
||||
printf("TeamDebugger::_HandleImageFileChanged(%ld)\n", imageID);
|
||||
// TODO: Reload the debug info!
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled)
|
||||
{
|
||||
@@ -710,6 +850,27 @@ TeamDebugger::_GetThreadHandler(thread_id threadID)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TeamDebugger::_AddImage(const ImageInfo& imageInfo)
|
||||
{
|
||||
LocatableFile* file = NULL;
|
||||
if (strchr(imageInfo.Name(), '/') != NULL)
|
||||
file = fFileManager->GetTargetFile(imageInfo.Name());
|
||||
Reference<LocatableFile> imageFileReference(file, true);
|
||||
|
||||
Image* image;
|
||||
status_t error = fTeam->AddImage(imageInfo, file, &image);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
ImageHandler* imageHandler = new(std::nothrow) ImageHandler(this, image);
|
||||
if (imageHandler != NULL)
|
||||
fImageHandlers->Insert(imageHandler);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::_NotifyUser(const char* title, const char* text,...)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
|
||||
class DebuggerInterface;
|
||||
class FileManager;
|
||||
class TeamDebugInfo;
|
||||
class TeamDebugModel;
|
||||
|
||||
@@ -64,6 +65,11 @@ private:
|
||||
virtual void ThreadStackTraceChanged(
|
||||
const ::Team::ThreadEvent& event);
|
||||
|
||||
private:
|
||||
struct ImageHandler;
|
||||
struct ImageHandlerHashDefinition;
|
||||
typedef OpenHashTable<ImageHandlerHashDefinition> ImageHandlerTable;
|
||||
|
||||
private:
|
||||
static status_t _DebugEventListenerEntry(void* data);
|
||||
status_t _DebugEventListener();
|
||||
@@ -79,14 +85,17 @@ private:
|
||||
bool _HandleImageDeleted(
|
||||
ImageDeletedEvent* event);
|
||||
|
||||
void _HandleImageFileChanged(image_id imageID);
|
||||
|
||||
void _HandleSetUserBreakpoint(target_addr_t address,
|
||||
bool enabled);
|
||||
void _HandleClearUserBreakpoint(
|
||||
target_addr_t address);
|
||||
|
||||
|
||||
ThreadHandler* _GetThreadHandler(thread_id threadID);
|
||||
|
||||
status_t _AddImage(const ImageInfo& imageInfo);
|
||||
|
||||
void _NotifyUser(const char* title,
|
||||
const char* text,...);
|
||||
|
||||
@@ -97,8 +106,10 @@ private:
|
||||
team_id fTeamID;
|
||||
ThreadHandlerTable fThreadHandlers;
|
||||
// protected by the team lock
|
||||
ImageHandlerTable* fImageHandlers;
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
TeamDebugInfo* fTeamDebugInfo;
|
||||
FileManager* fFileManager;
|
||||
Worker* fWorker;
|
||||
BreakpointManager* fBreakpointManager;
|
||||
thread_id fDebugEventListener;
|
||||
|
||||
@@ -33,7 +33,7 @@ DebuggerTeamDebugInfo::Init()
|
||||
|
||||
status_t
|
||||
DebuggerTeamDebugInfo::CreateImageDebugInfo(const ImageInfo& imageInfo,
|
||||
SpecificImageDebugInfo*& _imageDebugInfo)
|
||||
LocatableFile* imageFile, SpecificImageDebugInfo*& _imageDebugInfo)
|
||||
{
|
||||
DebuggerImageDebugInfo* debuggerInfo
|
||||
= new(std::nothrow) DebuggerImageDebugInfo(imageInfo,
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
status_t Init();
|
||||
|
||||
virtual status_t CreateImageDebugInfo(const ImageInfo& imageInfo,
|
||||
LocatableFile* imageFile,
|
||||
SpecificImageDebugInfo*& _imageDebugInfo);
|
||||
|
||||
private:
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "DwarfImageDebugInfo.h"
|
||||
#include "DwarfManager.h"
|
||||
#include "LocatableFile.h"
|
||||
|
||||
|
||||
DwarfTeamDebugInfo::DwarfTeamDebugInfo(Architecture* architecture)
|
||||
@@ -44,15 +45,16 @@ DwarfTeamDebugInfo::Init()
|
||||
|
||||
status_t
|
||||
DwarfTeamDebugInfo::CreateImageDebugInfo(const ImageInfo& imageInfo,
|
||||
SpecificImageDebugInfo*& _imageDebugInfo)
|
||||
LocatableFile* imageFile, SpecificImageDebugInfo*& _imageDebugInfo)
|
||||
{
|
||||
// We only want images that belong to shared objects.
|
||||
if (strchr(imageInfo.Name(), '/') == NULL)
|
||||
// We only like images whose file we can play with.
|
||||
BString filePath;
|
||||
if (imageFile == NULL || !imageFile->GetLocatedPath(filePath))
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
// try to load the DWARF file
|
||||
DwarfFile* file;
|
||||
status_t error = fManager->LoadFile(imageInfo.Name(), file);
|
||||
status_t error = fManager->LoadFile(filePath, file);
|
||||
if (error == B_OK)
|
||||
error = fManager->FinishLoading();
|
||||
if (error != B_OK)
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
status_t Init();
|
||||
|
||||
virtual status_t CreateImageDebugInfo(const ImageInfo& imageInfo,
|
||||
LocatableFile* imageFile,
|
||||
SpecificImageDebugInfo*& _imageDebugInfo);
|
||||
|
||||
private:
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
|
||||
class ImageInfo;
|
||||
class LocatableFile;
|
||||
class SpecificImageDebugInfo;
|
||||
|
||||
|
||||
@@ -17,6 +18,7 @@ public:
|
||||
virtual ~SpecificTeamDebugInfo();
|
||||
|
||||
virtual status_t CreateImageDebugInfo(const ImageInfo& imageInfo,
|
||||
LocatableFile* imageFile,
|
||||
SpecificImageDebugInfo*& _imageDebugInfo)
|
||||
= 0;
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ TeamDebugInfo::Init()
|
||||
|
||||
status_t
|
||||
TeamDebugInfo::LoadImageDebugInfo(const ImageInfo& imageInfo,
|
||||
ImageDebugInfo*& _imageDebugInfo)
|
||||
LocatableFile* imageFile, ImageDebugInfo*& _imageDebugInfo)
|
||||
{
|
||||
ImageDebugInfo* imageDebugInfo = new(std::nothrow) ImageDebugInfo(
|
||||
imageInfo);
|
||||
@@ -79,7 +79,7 @@ TeamDebugInfo::LoadImageDebugInfo(const ImageInfo& imageInfo,
|
||||
= fSpecificInfos.ItemAt(i); i++) {
|
||||
SpecificImageDebugInfo* specificImageInfo;
|
||||
status_t error = specificTeamInfo->CreateImageDebugInfo(imageInfo,
|
||||
specificImageInfo);
|
||||
imageFile, specificImageInfo);
|
||||
if (error == B_OK) {
|
||||
if (!imageDebugInfo->AddSpecificInfo(specificImageInfo)) {
|
||||
delete specificImageInfo;
|
||||
|
||||
@@ -15,6 +15,7 @@ class Architecture;
|
||||
class DebuggerInterface;
|
||||
class ImageDebugInfo;
|
||||
class ImageInfo;
|
||||
class LocatableFile;
|
||||
class SpecificTeamDebugInfo;
|
||||
|
||||
|
||||
@@ -28,6 +29,7 @@ public:
|
||||
status_t Init();
|
||||
|
||||
status_t LoadImageDebugInfo(const ImageInfo& imageInfo,
|
||||
LocatableFile* imageFile,
|
||||
ImageDebugInfo*& _imageDebugInfo);
|
||||
|
||||
private:
|
||||
|
||||
@@ -9,6 +9,7 @@ UsePrivateSystemHeaders ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) elf ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) types ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) util ] ;
|
||||
|
||||
|
||||
MergeObject Debugger_dwarf.o
|
||||
|
||||
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "FileManager.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "LocatableDirectory.h"
|
||||
#include "LocatableFile.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
|
||||
// #pragma mark - EntryPath
|
||||
|
||||
|
||||
struct FileManager::EntryPath {
|
||||
const char* directory;
|
||||
const char* name;
|
||||
|
||||
EntryPath(const char* directory, const char* name)
|
||||
:
|
||||
directory(directory),
|
||||
name(name)
|
||||
{
|
||||
}
|
||||
|
||||
EntryPath(const BString& directory, const BString& name)
|
||||
:
|
||||
directory(directory.Length() > 0 ? directory.String() : NULL),
|
||||
name(name.String())
|
||||
{
|
||||
}
|
||||
|
||||
EntryPath(const LocatableEntry* entry)
|
||||
:
|
||||
directory(entry->Parent() != NULL ? entry->Parent()->Path() : NULL),
|
||||
name(entry->Name())
|
||||
{
|
||||
}
|
||||
|
||||
EntryPath(const EntryPath& other)
|
||||
:
|
||||
directory(other.directory),
|
||||
name(other.name)
|
||||
{
|
||||
}
|
||||
|
||||
size_t HashValue() const
|
||||
{
|
||||
return StringUtils::HashValue(directory)
|
||||
^ StringUtils::HashValue(name);
|
||||
}
|
||||
|
||||
bool operator==(const EntryPath& other) const
|
||||
{
|
||||
if (directory != other.directory
|
||||
&& (directory == NULL || other.directory == NULL
|
||||
|| strcmp(directory, other.directory) != 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strcmp(name, other.name) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - EntryHashDefinition
|
||||
|
||||
|
||||
struct FileManager::EntryHashDefinition {
|
||||
typedef EntryPath KeyType;
|
||||
typedef LocatableEntry ValueType;
|
||||
|
||||
size_t HashKey(const EntryPath& key) const
|
||||
{
|
||||
return key.HashValue();
|
||||
}
|
||||
|
||||
size_t Hash(const LocatableEntry* value) const
|
||||
{
|
||||
return HashKey(EntryPath(value));
|
||||
}
|
||||
|
||||
bool Compare(const EntryPath& key, const LocatableEntry* value) const
|
||||
{
|
||||
return EntryPath(value) == key;
|
||||
}
|
||||
|
||||
HashTableLink<LocatableEntry>* GetLink(LocatableEntry* value) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - Domain
|
||||
|
||||
|
||||
class FileManager::Domain : private LocatableEntryOwner {
|
||||
public:
|
||||
Domain(FileManager* manager, bool isLocal)
|
||||
:
|
||||
fManager(manager),
|
||||
fIsLocal(isLocal)
|
||||
{
|
||||
}
|
||||
|
||||
~Domain()
|
||||
{
|
||||
LocatableEntry* entry = fEntries.Clear(true);
|
||||
while (entry != NULL) {
|
||||
LocatableEntry* next = entry->fNext;
|
||||
entry->RemoveReference();
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
|
||||
status_t Init()
|
||||
{
|
||||
status_t error = fEntries.Init();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
LocatableFile* GetFile(const BString& directoryPath, const BString& name)
|
||||
{
|
||||
BString normalizedDirectoryPath;
|
||||
_NormalizePath(directoryPath, normalizedDirectoryPath);
|
||||
LocatableFile* file = _GetFile(normalizedDirectoryPath, name);
|
||||
if (file == NULL)
|
||||
return NULL;
|
||||
|
||||
// try to auto-locate the file
|
||||
if (LocatableDirectory* directory = file->Parent()) {
|
||||
if (directory->State() == LOCATABLE_ENTRY_UNLOCATED) {
|
||||
// parent not yet located -- try locate with the entry's path
|
||||
BString path;
|
||||
file->GetPath(path);
|
||||
_LocateEntry(file, path, true, true);
|
||||
} else {
|
||||
// parent already located -- locate the entry in the parent
|
||||
BString locatedDirectoryPath;
|
||||
if (directory->GetLocatedPath(locatedDirectoryPath))
|
||||
_LocateEntryInParentDir(file, locatedDirectoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
LocatableFile* GetFile(const BString& path)
|
||||
{
|
||||
BString directoryPath;
|
||||
BString name;
|
||||
_SplitPath(path, directoryPath, name);
|
||||
return _GetFile(directoryPath, name);
|
||||
}
|
||||
|
||||
void EntryLocated(const BString& path, const BString& locatedPath)
|
||||
{
|
||||
BString directory;
|
||||
BString name;
|
||||
_SplitPath(path, directory, name);
|
||||
|
||||
LocatableEntry* entry = fEntries.Lookup(EntryPath(directory, name));
|
||||
if (entry == NULL)
|
||||
return;
|
||||
|
||||
_LocateEntry(entry, locatedPath, false, true);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool Lock()
|
||||
{
|
||||
return fManager->Lock();
|
||||
}
|
||||
|
||||
virtual void Unlock()
|
||||
{
|
||||
fManager->Unlock();
|
||||
}
|
||||
|
||||
virtual bool LocatableEntryUnused(LocatableEntry* entry)
|
||||
{
|
||||
fEntries.Remove(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _LocateDirectory(LocatableDirectory* directory,
|
||||
const BString& locatedPath)
|
||||
{
|
||||
if (directory == NULL
|
||||
|| directory->State() != LOCATABLE_ENTRY_UNLOCATED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// locate the parent, if possible, otherwise this directory
|
||||
BString locatedDirectory;
|
||||
BString locatedName;
|
||||
_SplitNormalizedPath(locatedPath, locatedDirectory, locatedName);
|
||||
if (locatedName != directory->Name()
|
||||
|| !_LocateDirectory(directory->Parent(), locatedDirectory)) {
|
||||
directory->SetLocatedPath(locatedPath, true);
|
||||
_LocateEntries(directory, locatedPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _LocateEntry(LocatableEntry* entry, const BString& locatedPath,
|
||||
bool implicit, bool locateAncestors)
|
||||
{
|
||||
if (implicit && entry->State() == LOCATABLE_ENTRY_LOCATED_EXPLICITLY)
|
||||
return false;
|
||||
|
||||
struct stat st;
|
||||
if (stat(locatedPath, &st) != 0)
|
||||
return false;
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
LocatableDirectory* directory
|
||||
= dynamic_cast<LocatableDirectory*>(entry);
|
||||
if (directory == NULL)
|
||||
return false;
|
||||
entry->SetLocatedPath(locatedPath, implicit);
|
||||
} else if (S_ISREG(st.st_mode)) {
|
||||
LocatableFile* file = dynamic_cast<LocatableFile*>(entry);
|
||||
if (file == NULL)
|
||||
return false;
|
||||
entry->SetLocatedPath(locatedPath, implicit);
|
||||
}
|
||||
|
||||
// locate the ancestor directories, if requested
|
||||
if (locateAncestors) {
|
||||
BString locatedDirectory;
|
||||
BString locatedName;
|
||||
_SplitPath(locatedPath, locatedDirectory, locatedName);
|
||||
if (locatedName == entry->Name())
|
||||
_LocateDirectory(entry->Parent(), locatedDirectory);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _LocateEntryInParentDir(LocatableEntry* entry,
|
||||
const BString& locatedDirectoryPath)
|
||||
{
|
||||
// construct the located entry path
|
||||
BString locatedEntryPath(locatedDirectoryPath);
|
||||
int32 pathLength = locatedEntryPath.Length();
|
||||
if (pathLength >= 1 && locatedEntryPath.ByteAt(pathLength - 1) != '/')
|
||||
locatedEntryPath << '/';
|
||||
locatedEntryPath << entry->Name();
|
||||
|
||||
return _LocateEntry(entry, locatedEntryPath, true, false);
|
||||
}
|
||||
|
||||
void _LocateEntries(LocatableDirectory* directory,
|
||||
const BString& locatedPath)
|
||||
{
|
||||
for (LocatableEntryList::ConstIterator it
|
||||
= directory->Entries().GetIterator();
|
||||
LocatableEntry* entry = it.Next();) {
|
||||
if (entry->State() == LOCATABLE_ENTRY_LOCATED_EXPLICITLY)
|
||||
continue;
|
||||
|
||||
if (_LocateEntryInParentDir(entry, locatedPath)) {
|
||||
// recurse for directories
|
||||
if (LocatableDirectory* subDir
|
||||
= dynamic_cast<LocatableDirectory*>(entry)) {
|
||||
BString locatedEntryPath;
|
||||
if (subDir->GetLocatedPath(locatedEntryPath))
|
||||
_LocateEntries(subDir, locatedEntryPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LocatableFile* _GetFile(const BString& directoryPath, const BString& name)
|
||||
{
|
||||
// if already know return the file
|
||||
LocatableEntry* entry = fEntries.Lookup(EntryPath(directoryPath, name));
|
||||
if (entry != NULL) {
|
||||
LocatableFile* file = dynamic_cast<LocatableFile*>(entry);
|
||||
if (file == NULL)
|
||||
return NULL;
|
||||
|
||||
file->AcquireReference();
|
||||
return file;
|
||||
}
|
||||
|
||||
// no such file yet -- create it
|
||||
BString normalizedDirPath;
|
||||
_NormalizePath(directoryPath, normalizedDirPath);
|
||||
LocatableDirectory* directory = _GetDirectory(normalizedDirPath);
|
||||
if (directory == NULL)
|
||||
return NULL;
|
||||
|
||||
LocatableFile* file = new(std::nothrow) LocatableFile(this, directory,
|
||||
name);
|
||||
if (file == NULL) {
|
||||
directory->ReleaseReference();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fEntries.Insert(file);
|
||||
return file;
|
||||
}
|
||||
|
||||
LocatableDirectory* _GetDirectory(const BString& path)
|
||||
{
|
||||
BString directoryPath;
|
||||
BString fileName;
|
||||
_SplitNormalizedPath(path, directoryPath, fileName);
|
||||
|
||||
// if already know return the directory
|
||||
LocatableEntry* entry
|
||||
= fEntries.Lookup(EntryPath(directoryPath, fileName));
|
||||
if (entry != NULL) {
|
||||
LocatableDirectory* directory
|
||||
= dynamic_cast<LocatableDirectory*>(entry);
|
||||
if (directory == NULL)
|
||||
return NULL;
|
||||
directory->AcquireReference();
|
||||
return directory;
|
||||
}
|
||||
|
||||
// get the parent directory
|
||||
LocatableDirectory* parentDirectory = NULL;
|
||||
if (directoryPath.Length() > 0) {
|
||||
parentDirectory = _GetDirectory(directoryPath);
|
||||
if (parentDirectory == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// create a new directory
|
||||
LocatableDirectory* directory = new(std::nothrow) LocatableDirectory(
|
||||
this, parentDirectory, path);
|
||||
if (directory == NULL) {
|
||||
parentDirectory->ReleaseReference();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// auto-locate, if possible
|
||||
if (fIsLocal) {
|
||||
BString dirPath;
|
||||
directory->GetPath(dirPath);
|
||||
directory->SetLocatedPath(dirPath, false);
|
||||
} else if (parentDirectory != NULL
|
||||
&& parentDirectory->State() != LOCATABLE_ENTRY_UNLOCATED) {
|
||||
// TODO:...
|
||||
}
|
||||
|
||||
fEntries.Insert(directory);
|
||||
return directory;
|
||||
}
|
||||
|
||||
void _NormalizePath(const BString& path, BString& _normalizedPath)
|
||||
{
|
||||
BString normalizedPath;
|
||||
char* buffer = normalizedPath.LockBuffer(path.Length());
|
||||
int32 outIndex = 0;
|
||||
const char* remaining = path.String();
|
||||
|
||||
while (*remaining != '\0') {
|
||||
// collapse repeated slashes
|
||||
if (*remaining == '/') {
|
||||
buffer[outIndex++] = '/';
|
||||
remaining++;
|
||||
while (*remaining == '/')
|
||||
remaining++;
|
||||
}
|
||||
|
||||
if (*remaining == '\0') {
|
||||
// remove trailing slash (unless it's "/" only)
|
||||
if (outIndex > 1)
|
||||
outIndex--;
|
||||
break;
|
||||
}
|
||||
|
||||
// skip "." components
|
||||
if (*remaining == '.') {
|
||||
if (remaining[1] == '\0')
|
||||
break;
|
||||
|
||||
if (remaining[1] == '/') {
|
||||
remaining += 2;
|
||||
while (*remaining == '/')
|
||||
remaining++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// copy path component
|
||||
while (*remaining != '\0' && *remaining != '/')
|
||||
buffer[outIndex++] = *(remaining++);
|
||||
}
|
||||
|
||||
// If the path didn't change, use the original path (BString's copy on
|
||||
// write mechanism) rather than the new string.
|
||||
if (outIndex == path.Length()) {
|
||||
_normalizedPath = path;
|
||||
} else {
|
||||
normalizedPath.UnlockBuffer(outIndex);
|
||||
_normalizedPath = normalizedPath;
|
||||
}
|
||||
}
|
||||
|
||||
void _SplitPath(const BString& path, BString& _directory, BString& _name)
|
||||
{
|
||||
BString normalized;
|
||||
_NormalizePath(path, normalized);
|
||||
_SplitNormalizedPath(normalized, _directory, _name);
|
||||
}
|
||||
|
||||
void _SplitNormalizedPath(const BString& path, BString& _directory,
|
||||
BString& _name)
|
||||
{
|
||||
// handle single component (including root dir) cases
|
||||
int32 lastSlash = path.FindLast('/');
|
||||
if (lastSlash < 0 || path.Length() == 1) {
|
||||
_directory = (const char*)NULL;
|
||||
_name = path;
|
||||
return;
|
||||
}
|
||||
|
||||
// handle root dir + one component and multi component cases
|
||||
if (lastSlash == 0)
|
||||
_directory = "/";
|
||||
else
|
||||
_directory.SetTo(path, lastSlash);
|
||||
_name = path.String() + (lastSlash + 1);
|
||||
}
|
||||
|
||||
private:
|
||||
FileManager* fManager;
|
||||
LocatableEntryTable fEntries;
|
||||
bool fIsLocal;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - FileManager
|
||||
|
||||
|
||||
FileManager::FileManager()
|
||||
:
|
||||
fLock("file manager"),
|
||||
fTargetDomain(NULL),
|
||||
fSourceDomain(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FileManager::~FileManager()
|
||||
{
|
||||
delete fTargetDomain;
|
||||
delete fSourceDomain;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FileManager::Init(bool targetIsLocal)
|
||||
{
|
||||
status_t error = fLock.InitCheck();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create target domain
|
||||
fTargetDomain = new(std::nothrow) Domain(this, targetIsLocal);
|
||||
if (fTargetDomain == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
error = fTargetDomain->Init();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create source domain
|
||||
fSourceDomain = new(std::nothrow) Domain(this, false);
|
||||
if (fSourceDomain == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
error = fSourceDomain->Init();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
LocatableFile*
|
||||
FileManager::GetTargetFile(const BString& directory, const BString& name)
|
||||
{
|
||||
AutoLocker<FileManager> locker(this);
|
||||
return fTargetDomain->GetFile(directory, name);
|
||||
}
|
||||
|
||||
|
||||
LocatableFile*
|
||||
FileManager::GetTargetFile(const BString& path)
|
||||
{
|
||||
AutoLocker<FileManager> locker(this);
|
||||
return fTargetDomain->GetFile(path);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FileManager::TargetEntryLocated(const BString& path, const BString& locatedPath)
|
||||
{
|
||||
AutoLocker<FileManager> locker(this);
|
||||
fTargetDomain->EntryLocated(path, locatedPath);
|
||||
}
|
||||
|
||||
|
||||
LocatableFile*
|
||||
FileManager::GetSourceFile(const BString& directory, const BString& name)
|
||||
{
|
||||
AutoLocker<FileManager> locker(this);
|
||||
return fSourceDomain->GetFile(directory, name);
|
||||
}
|
||||
|
||||
|
||||
LocatableFile*
|
||||
FileManager::GetSourceFile(const BString& path)
|
||||
{
|
||||
AutoLocker<FileManager> locker(this);
|
||||
return fSourceDomain->GetFile(path);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FileManager::SourceEntryLocated(const BString& path, const BString& locatedPath)
|
||||
{
|
||||
AutoLocker<FileManager> locker(this);
|
||||
fSourceDomain->EntryLocated(path, locatedPath);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef FILE_MANAGER_H
|
||||
#define FILE_MANAGER_H
|
||||
|
||||
#include <Locker.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
|
||||
class LocatableFile;
|
||||
|
||||
|
||||
class FileManager {
|
||||
public:
|
||||
FileManager();
|
||||
~FileManager();
|
||||
|
||||
status_t Init(bool targetIsLocal);
|
||||
|
||||
bool Lock() { return fLock.Lock(); }
|
||||
void Unlock() { fLock.Unlock(); }
|
||||
|
||||
LocatableFile* GetTargetFile(const BString& directory,
|
||||
const BString& name);
|
||||
// returns a reference
|
||||
LocatableFile* GetTargetFile(const BString& path);
|
||||
// returns a reference
|
||||
void TargetEntryLocated(const BString& path,
|
||||
const BString& locatedPath);
|
||||
|
||||
LocatableFile* GetSourceFile(const BString& directory,
|
||||
const BString& name);
|
||||
// returns a reference
|
||||
LocatableFile* GetSourceFile(const BString& path);
|
||||
// returns a reference
|
||||
void SourceEntryLocated(const BString& path,
|
||||
const BString& locatedPath);
|
||||
|
||||
private:
|
||||
struct EntryPath;
|
||||
struct EntryHashDefinition;
|
||||
class Domain;
|
||||
|
||||
typedef OpenHashTable<EntryHashDefinition> LocatableEntryTable;
|
||||
|
||||
private:
|
||||
BLocker fLock;
|
||||
Domain* fTargetDomain;
|
||||
Domain* fSourceDomain;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // FILE_MANAGER_H
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "LocatableDirectory.h"
|
||||
|
||||
|
||||
LocatableDirectory::LocatableDirectory(LocatableEntryOwner* owner,
|
||||
LocatableDirectory* parent, const BString& path)
|
||||
:
|
||||
LocatableEntry(owner, parent),
|
||||
fPath(path),
|
||||
fLocatedPath()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LocatableDirectory::~LocatableDirectory()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
LocatableDirectory::Name() const
|
||||
{
|
||||
int32 lastSlash = fPath.FindLast('/');
|
||||
// return -1, if not found
|
||||
return fPath.String() + (lastSlash + 1);
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
LocatableDirectory::Path() const
|
||||
{
|
||||
return fPath.String();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocatableDirectory::GetPath(BString& _path) const
|
||||
{
|
||||
_path = fPath;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
LocatableDirectory::GetLocatedPath(BString& _path) const
|
||||
{
|
||||
if (fLocatedPath.Length() == 0)
|
||||
return false;
|
||||
_path = fLocatedPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocatableDirectory::SetLocatedPath(const BString& path, bool implicit)
|
||||
{
|
||||
fLocatedPath = path;
|
||||
fState = implicit
|
||||
? LOCATABLE_ENTRY_LOCATED_IMPLICITLY
|
||||
: LOCATABLE_ENTRY_LOCATED_EXPLICITLY;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocatableDirectory::AddEntry(LocatableEntry* entry)
|
||||
{
|
||||
fEntries.Add(entry);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocatableDirectory::RemoveEntry(LocatableEntry* entry)
|
||||
{
|
||||
fEntries.Remove(entry);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef LOCATABLE_DIRECTORY_H
|
||||
#define LOCATABLE_DIRECTORY_H
|
||||
|
||||
#include "LocatableEntry.h"
|
||||
|
||||
|
||||
class LocatableDirectory : public LocatableEntry {
|
||||
public:
|
||||
LocatableDirectory(LocatableEntryOwner* owner,
|
||||
LocatableDirectory* parent,
|
||||
const BString& path);
|
||||
~LocatableDirectory();
|
||||
|
||||
virtual const char* Name() const;
|
||||
const char* Path() const;
|
||||
void GetPath(BString& _path) const;
|
||||
|
||||
// mutable (requires locking)
|
||||
virtual bool GetLocatedPath(BString& _path) const;
|
||||
virtual void SetLocatedPath(const BString& path,
|
||||
bool implicit);
|
||||
|
||||
void AddEntry(LocatableEntry* entry);
|
||||
void RemoveEntry(LocatableEntry* entry);
|
||||
const LocatableEntryList& Entries() const { return fEntries; }
|
||||
|
||||
private:
|
||||
BString fPath;
|
||||
BString fLocatedPath;
|
||||
LocatableEntryList fEntries;
|
||||
};
|
||||
|
||||
|
||||
#endif // LOCATABLE_DIRECTORY_H
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "LocatableEntry.h"
|
||||
|
||||
#include "AutoLocker.h"
|
||||
|
||||
#include "LocatableDirectory.h"
|
||||
|
||||
|
||||
// #pragma mark - LocatableEntryOwner
|
||||
|
||||
|
||||
LocatableEntryOwner::~LocatableEntryOwner()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - LocatableEntry
|
||||
|
||||
|
||||
LocatableEntry::LocatableEntry(LocatableEntryOwner* owner,
|
||||
LocatableDirectory* parent)
|
||||
:
|
||||
fOwner(owner),
|
||||
fParent(parent),
|
||||
fState(LOCATABLE_ENTRY_UNLOCATED)
|
||||
{
|
||||
if (fParent != NULL)
|
||||
fParent->AcquireReference();
|
||||
}
|
||||
|
||||
|
||||
LocatableEntry::~LocatableEntry()
|
||||
{
|
||||
if (fParent != NULL)
|
||||
fParent->ReleaseReference();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocatableEntry::LastReferenceReleased()
|
||||
{
|
||||
AutoLocker<LocatableEntryOwner> locker(fOwner);
|
||||
if (CountReferences() == 0 && fOwner->LocatableEntryUnused(this))
|
||||
delete this;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef LOCATABLE_ENTRY_H
|
||||
#define LOCATABLE_ENTRY_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
|
||||
enum locatable_entry_state {
|
||||
LOCATABLE_ENTRY_UNLOCATED,
|
||||
LOCATABLE_ENTRY_LOCATED_IMPLICITLY,
|
||||
LOCATABLE_ENTRY_LOCATED_EXPLICITLY
|
||||
};
|
||||
|
||||
|
||||
class LocatableDirectory;
|
||||
class LocatableEntry;
|
||||
|
||||
|
||||
class LocatableEntryOwner {
|
||||
public:
|
||||
virtual ~LocatableEntryOwner();
|
||||
|
||||
virtual bool Lock() = 0;
|
||||
virtual void Unlock() = 0;
|
||||
|
||||
virtual bool LocatableEntryUnused(LocatableEntry* entry) = 0;
|
||||
};
|
||||
|
||||
|
||||
class LocatableEntry : public Referenceable,
|
||||
public DoublyLinkedListLinkImpl<LocatableEntry>,
|
||||
public HashTableLink<LocatableEntry> {
|
||||
public:
|
||||
LocatableEntry(LocatableEntryOwner* owner,
|
||||
LocatableDirectory* parent);
|
||||
~LocatableEntry();
|
||||
|
||||
LocatableDirectory* Parent() const { return fParent; }
|
||||
virtual const char* Name() const = 0;
|
||||
|
||||
// mutable (requires locking)
|
||||
locatable_entry_state State() const { return fState; }
|
||||
virtual bool GetLocatedPath(BString& _path) const = 0;
|
||||
virtual void SetLocatedPath(const BString& path,
|
||||
bool implicit) = 0;
|
||||
|
||||
protected:
|
||||
virtual void LastReferenceReleased();
|
||||
|
||||
protected:
|
||||
LocatableEntryOwner* fOwner;
|
||||
LocatableDirectory* fParent;
|
||||
locatable_entry_state fState;
|
||||
};
|
||||
|
||||
|
||||
typedef DoublyLinkedList<LocatableEntry> LocatableEntryList;
|
||||
|
||||
|
||||
#endif // LOCATABLE_ENTRY_H
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "LocatableFile.h"
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "LocatableDirectory.h"
|
||||
|
||||
|
||||
// #pragma mark - LocatableFile
|
||||
|
||||
|
||||
LocatableFile::LocatableFile(LocatableEntryOwner* owner,
|
||||
LocatableDirectory* directory, const BString& name)
|
||||
:
|
||||
LocatableEntry(owner, directory),
|
||||
fName(name),
|
||||
fLocatedPath(),
|
||||
fListeners(8)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LocatableFile::~LocatableFile()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
LocatableFile::Name() const
|
||||
{
|
||||
return fName.String();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocatableFile::GetPath(BString& _path) const
|
||||
{
|
||||
fParent->GetPath(_path);
|
||||
_path << '/' << fName;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
LocatableFile::GetLocatedPath(BString& _path) const
|
||||
{
|
||||
AutoLocker<LocatableEntryOwner> locker(fOwner);
|
||||
|
||||
if (fLocatedPath.Length() > 0) {
|
||||
_path = fLocatedPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!fParent->GetLocatedPath(_path))
|
||||
return false;
|
||||
|
||||
_path << '/' << fName;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocatableFile::SetLocatedPath(const BString& path, bool implicit)
|
||||
{
|
||||
// called with owner already locked
|
||||
|
||||
if (implicit) {
|
||||
fLocatedPath = (const char*)NULL;
|
||||
fState = LOCATABLE_ENTRY_LOCATED_IMPLICITLY;
|
||||
} else {
|
||||
fLocatedPath = path;
|
||||
fState = LOCATABLE_ENTRY_LOCATED_EXPLICITLY;
|
||||
}
|
||||
|
||||
_NotifyListeners();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
LocatableFile::AddListener(Listener* listener)
|
||||
{
|
||||
AutoLocker<LocatableEntryOwner> locker(fOwner);
|
||||
return fListeners.AddItem(listener);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocatableFile::RemoveListener(Listener* listener)
|
||||
{
|
||||
AutoLocker<LocatableEntryOwner> locker(fOwner);
|
||||
fListeners.RemoveItem(listener);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocatableFile::_NotifyListeners()
|
||||
{
|
||||
for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
|
||||
fListeners.ItemAt(i)->LocatableFileChanged(this);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Listener
|
||||
|
||||
|
||||
LocatableFile::Listener::~Listener()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef LOCATABLE_FILE_H
|
||||
#define LOCATABLE_FILE_H
|
||||
|
||||
#include <ObjectList.h>
|
||||
|
||||
#include "LocatableEntry.h"
|
||||
|
||||
|
||||
class LocatableFile : public LocatableEntry {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
public:
|
||||
LocatableFile(LocatableEntryOwner* owner,
|
||||
LocatableDirectory* directory,
|
||||
const BString& name);
|
||||
~LocatableFile();
|
||||
|
||||
virtual const char* Name() const;
|
||||
void GetPath(BString& _path) const;
|
||||
|
||||
// mutable (requires/does locking)
|
||||
virtual bool GetLocatedPath(BString& _path) const;
|
||||
virtual void SetLocatedPath(const BString& path,
|
||||
bool implicit);
|
||||
|
||||
bool AddListener(Listener* listener);
|
||||
void RemoveListener(Listener* listener);
|
||||
|
||||
private:
|
||||
typedef BObjectList<Listener> ListenerList;
|
||||
|
||||
private:
|
||||
void _NotifyListeners();
|
||||
|
||||
private:
|
||||
BString fName;
|
||||
BString fLocatedPath;
|
||||
ListenerList fListeners;
|
||||
};
|
||||
|
||||
|
||||
class LocatableFile::Listener {
|
||||
public:
|
||||
virtual ~Listener();
|
||||
|
||||
virtual void LocatableFileChanged(LocatableFile* file) = 0;
|
||||
// called with lock held
|
||||
};
|
||||
|
||||
|
||||
#endif // LOCATABLE_FILE_H
|
||||
@@ -6,23 +6,29 @@
|
||||
#include "Image.h"
|
||||
|
||||
#include "ImageDebugInfo.h"
|
||||
#include "LocatableFile.h"
|
||||
#include "Team.h"
|
||||
|
||||
|
||||
Image::Image(Team* team,const ImageInfo& imageInfo)
|
||||
Image::Image(Team* team,const ImageInfo& imageInfo, LocatableFile* imageFile)
|
||||
:
|
||||
fTeam(team),
|
||||
fInfo(imageInfo),
|
||||
fImageFile(imageFile),
|
||||
fDebugInfo(NULL),
|
||||
fDebugInfoState(IMAGE_DEBUG_INFO_NOT_LOADED)
|
||||
{
|
||||
if (fImageFile != NULL)
|
||||
fImageFile->AcquireReference();
|
||||
}
|
||||
|
||||
|
||||
Image::~Image()
|
||||
{
|
||||
if (fDebugInfo != NULL)
|
||||
fDebugInfo->RemoveReference();
|
||||
fDebugInfo->ReleaseReference();
|
||||
if (fImageFile != NULL)
|
||||
fImageFile->ReleaseReference();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -22,12 +22,14 @@ enum image_debug_info_state {
|
||||
|
||||
|
||||
class ImageDebugInfo;
|
||||
class LocatableFile;
|
||||
class Team;
|
||||
|
||||
|
||||
class Image : public Referenceable, public DoublyLinkedListLinkImpl<Image> {
|
||||
public:
|
||||
Image(Team* team, const ImageInfo& imageInfo);
|
||||
Image(Team* team, const ImageInfo& imageInfo,
|
||||
LocatableFile* imageFile);
|
||||
~Image();
|
||||
|
||||
status_t Init();
|
||||
@@ -37,6 +39,7 @@ public:
|
||||
image_id ID() const { return fInfo.ImageID(); }
|
||||
const char* Name() const { return fInfo.Name(); }
|
||||
const ImageInfo& Info() const { return fInfo; }
|
||||
LocatableFile* ImageFile() const { return fImageFile; }
|
||||
|
||||
bool ContainsAddress(target_addr_t address) const;
|
||||
|
||||
@@ -50,6 +53,7 @@ public:
|
||||
private:
|
||||
Team* fTeam;
|
||||
ImageInfo fInfo;
|
||||
LocatableFile* fImageFile;
|
||||
// mutable
|
||||
ImageDebugInfo* fDebugInfo;
|
||||
image_debug_info_state fDebugInfoState;
|
||||
|
||||
@@ -123,18 +123,11 @@ Team::Threads() const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Team::AddImage(Image* image)
|
||||
{
|
||||
fImages.Add(image);
|
||||
_NotifyImageAdded(image);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Team::AddImage(const ImageInfo& imageInfo, Image** _image)
|
||||
Team::AddImage(const ImageInfo& imageInfo, LocatableFile* imageFile,
|
||||
Image** _image)
|
||||
{
|
||||
Image* image = new(std::nothrow) Image(this, imageInfo);
|
||||
Image* image = new(std::nothrow) Image(this, imageInfo, imageFile);
|
||||
if (image == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
@@ -144,7 +137,8 @@ Team::AddImage(const ImageInfo& imageInfo, Image** _image)
|
||||
return error;
|
||||
}
|
||||
|
||||
AddImage(image);
|
||||
fImages.Add(image);
|
||||
_NotifyImageAdded(image);
|
||||
|
||||
if (_image != NULL)
|
||||
*_image = image;
|
||||
|
||||
@@ -28,6 +28,7 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
class LocatableFile;
|
||||
class TeamDebugInfo;
|
||||
|
||||
|
||||
@@ -58,8 +59,8 @@ public:
|
||||
Thread* ThreadByID(thread_id threadID) const;
|
||||
const ThreadList& Threads() const;
|
||||
|
||||
void AddImage(Image* image);
|
||||
status_t AddImage(const ImageInfo& imageInfo,
|
||||
LocatableFile* imageFile,
|
||||
Image** _image = NULL);
|
||||
void RemoveImage(Image* image);
|
||||
bool RemoveImage(image_id imageID);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected]. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "StringUtils.h"
|
||||
|
||||
|
||||
// from the Dragon Book: a slightly modified hashpjw()
|
||||
/*static*/ uint32
|
||||
StringUtils::HashValue(const char* string)
|
||||
{
|
||||
if (string == NULL)
|
||||
return 0;
|
||||
|
||||
uint32 h = 0;
|
||||
|
||||
for (; *string; string++) {
|
||||
uint32 g = h & 0xf0000000;
|
||||
if (g)
|
||||
h ^= g >> 24;
|
||||
h = (h << 4) + *string;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected]. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef STRING_UTILS_H
|
||||
#define STRING_UTILS_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
|
||||
class StringUtils {
|
||||
public:
|
||||
static uint32 HashValue(const char* string);
|
||||
static uint32 HashValue(const BString& string);
|
||||
};
|
||||
|
||||
|
||||
/*static*/ inline uint32
|
||||
StringUtils::HashValue(const BString& string)
|
||||
{
|
||||
return HashValue(string.String());
|
||||
}
|
||||
|
||||
|
||||
#endif // STRING_UTILS_H
|
||||
Reference in New Issue
Block a user