Copied Ingo's netfs from the dark pit in which it was forgotten to something
more visible and ported it to the current UserlandFS server (and GCC4). It still uses the R5 file system API, which the UserlandFS conveniently still provides support for. It compiles and links, but is otherwise still untested. The changes I am alsmost confident that I didn't change any semantics. That is unless HashMap, HashString and DoublyLinkedList work differently enough to make any of the netfs code break. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35081 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
783a5c71b1
commit
5a1d355fdf
@ -6,6 +6,7 @@ SubInclude HAIKU_TOP src add-ons kernel file_systems ext2 ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems fat ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems googlefs ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems iso9660 ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems netfs ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems nfs ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems ntfs ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems packagefs ;
|
||||
|
8
src/add-ons/kernel/file_systems/netfs/Jamfile
Normal file
8
src/add-ons/kernel/file_systems/netfs/Jamfile
Normal file
@ -0,0 +1,8 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel file_systems netfs ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems netfs
|
||||
authentication_server ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems netfs client ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems netfs netfs_config ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems netfs netfs_server_prefs ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems netfs server ;
|
@ -0,0 +1,238 @@
|
||||
// AuthenticationPanel.cpp
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Screen.h>
|
||||
|
||||
#include <Box.h>
|
||||
#include <Button.h>
|
||||
#include <CheckBox.h>
|
||||
#include <Message.h>
|
||||
#include <String.h>
|
||||
#include <StringView.h>
|
||||
#include <TextControl.h>
|
||||
|
||||
#include "AuthenticationPanel.h"
|
||||
|
||||
enum {
|
||||
MSG_PANEL_OK,
|
||||
MSG_PANEL_CANCEL,
|
||||
};
|
||||
|
||||
// constructor
|
||||
AuthenticationPanel::AuthenticationPanel(BRect frame)
|
||||
: Panel(frame, "Name Panel",
|
||||
B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
|
||||
B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE | B_NOT_ZOOMABLE),
|
||||
fCancelled(false),
|
||||
fExitSem(B_ERROR)
|
||||
{
|
||||
fExitSem = create_sem(0, "Authentication Panel");
|
||||
|
||||
BRect controlFrame(0.0, 0.0, frame.Width(), 15.0);
|
||||
|
||||
fNameTC = new BTextControl(controlFrame, "name", "Username", "", NULL,
|
||||
B_FOLLOW_LEFT | B_FOLLOW_RIGHT);
|
||||
|
||||
fPassTC = new BTextControl(controlFrame, "pass", "Password", "", NULL,
|
||||
B_FOLLOW_LEFT | B_FOLLOW_RIGHT);
|
||||
|
||||
fKeepUsingCB = new BCheckBox(controlFrame, "again",
|
||||
"Use login for all shares of this host",
|
||||
NULL, B_FOLLOW_LEFT | B_FOLLOW_RIGHT);
|
||||
|
||||
BRect buttonFrame(0.0, 0.0, 20.0, 15.0);
|
||||
fOkB = new BButton(buttonFrame, "ok", "OK",
|
||||
new BMessage(MSG_PANEL_OK));
|
||||
fCancelB = new BButton(buttonFrame, "cancel", "Cancel",
|
||||
new BMessage(MSG_PANEL_CANCEL));
|
||||
|
||||
}
|
||||
|
||||
// destructor
|
||||
AuthenticationPanel::~AuthenticationPanel()
|
||||
{
|
||||
delete_sem(fExitSem);
|
||||
}
|
||||
|
||||
// QuitRequested
|
||||
bool
|
||||
AuthenticationPanel::QuitRequested()
|
||||
{
|
||||
fCancelled = true;
|
||||
release_sem(fExitSem);
|
||||
return false;
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
AuthenticationPanel::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case MSG_PANEL_CANCEL:
|
||||
Cancel();
|
||||
break;
|
||||
case MSG_PANEL_OK: {
|
||||
release_sem(fExitSem);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Panel::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
// GetAuthentication
|
||||
bool
|
||||
AuthenticationPanel::GetAuthentication(const char* server,
|
||||
const char* share,
|
||||
const char* previousUser,
|
||||
const char* previousPass,
|
||||
bool previousKeep,
|
||||
bool badPassword,
|
||||
char* user, char* pass, bool* keep)
|
||||
{
|
||||
// configure panel and layout controls
|
||||
BString helper("Enter login for: ");
|
||||
helper << (server ? server : "<unkown host>") << "/";
|
||||
helper << (share ? share : "<unkown share>");
|
||||
|
||||
// ignore the previous password, if it didn't work
|
||||
if (badPassword)
|
||||
previousPass = NULL;
|
||||
|
||||
SetTitle(helper.String());
|
||||
|
||||
BPoint offset(0.0, 5.0);
|
||||
|
||||
fNameTC->SetText(previousUser ? previousUser : "");
|
||||
fNameTC->ResizeToPreferred();
|
||||
fNameTC->MoveTo(BPoint(10.0, 10.0));
|
||||
|
||||
fPassTC->SetText(previousPass ? previousPass : "");
|
||||
fPassTC->ResizeToPreferred();
|
||||
fPassTC->MoveTo(fNameTC->Frame().LeftBottom() + offset);
|
||||
|
||||
fKeepUsingCB->SetValue(previousKeep);
|
||||
fKeepUsingCB->ResizeToPreferred();
|
||||
fKeepUsingCB->MoveTo(fPassTC->Frame().LeftBottom() + offset);
|
||||
|
||||
fCancelB->ResizeToPreferred();
|
||||
|
||||
fOkB->ResizeToPreferred();
|
||||
fOkB->MoveTo(fKeepUsingCB->Frame().RightBottom() + offset + offset - fOkB->Frame().RightTop());
|
||||
|
||||
fCancelB->MoveTo(fOkB->Frame().LeftTop() - BPoint(10.0, 0.0) - fCancelB->Frame().RightTop());
|
||||
|
||||
BRect frame(fNameTC->Frame().LeftTop(), fOkB->Frame().RightBottom());
|
||||
|
||||
// work arround buggy BTextControl resizing
|
||||
BRect nameFrame = fNameTC->Frame();
|
||||
BRect passFrame = fPassTC->Frame();
|
||||
|
||||
nameFrame.right = nameFrame.left + frame.Width();
|
||||
passFrame.right = passFrame.left + frame.Width();
|
||||
|
||||
float divider = fNameTC->Divider();
|
||||
|
||||
if (fPassTC->Divider() > divider)
|
||||
divider = fPassTC->Divider();
|
||||
|
||||
delete fNameTC;
|
||||
fNameTC = new BTextControl(nameFrame, "name", "Username", "", NULL,
|
||||
B_FOLLOW_LEFT | B_FOLLOW_RIGHT);
|
||||
fNameTC->SetText(previousUser ? previousUser : "");
|
||||
|
||||
delete fPassTC;
|
||||
fPassTC = new BTextControl(passFrame, "pass", "Password", "", NULL,
|
||||
B_FOLLOW_LEFT | B_FOLLOW_RIGHT);
|
||||
|
||||
fPassTC->TextView()->HideTyping(true);
|
||||
fPassTC->SetText(previousPass ? previousPass : "");
|
||||
|
||||
fNameTC->SetDivider(divider);
|
||||
fPassTC->SetDivider(divider);
|
||||
|
||||
|
||||
// create background view
|
||||
frame.InsetBy(-10.0, -10.0);
|
||||
|
||||
BBox* bg = new BBox(frame, "bg", B_FOLLOW_ALL,
|
||||
B_FRAME_EVENTS | B_WILL_DRAW | B_NAVIGABLE_JUMP,
|
||||
B_PLAIN_BORDER);
|
||||
|
||||
bg->AddChild(fNameTC);
|
||||
bg->AddChild(fPassTC);
|
||||
bg->AddChild(fKeepUsingCB);
|
||||
|
||||
bg->AddChild(fOkB);
|
||||
bg->AddChild(fCancelB);
|
||||
|
||||
frame.OffsetTo(-10000.0, -10000.0);
|
||||
frame = _CalculateFrame(frame);
|
||||
MoveTo(frame.LeftTop());
|
||||
ResizeTo(frame.Width(), frame.Height());
|
||||
|
||||
AddChild(bg);
|
||||
SetDefaultButton(fOkB);
|
||||
fNameTC->MakeFocus(true);
|
||||
|
||||
// start window thread
|
||||
Show();
|
||||
|
||||
// let the window jitter, if the previous password was invalid
|
||||
if (badPassword) {
|
||||
BPoint leftTop = Frame().LeftTop();
|
||||
const float jitterOffsets[] = { -10, 0, 10, 0 };
|
||||
const int32 jitterOffsetCount = sizeof(jitterOffsets) / sizeof(float);
|
||||
for (int32 i = 0; i < 30; i++) {
|
||||
float offset = jitterOffsets[i % jitterOffsetCount];
|
||||
MoveTo(leftTop.x + offset, leftTop.y);
|
||||
snooze(10000);
|
||||
}
|
||||
MoveTo(leftTop);
|
||||
}
|
||||
|
||||
// block calling thread
|
||||
acquire_sem(fExitSem);
|
||||
|
||||
// window wants to quit
|
||||
Lock();
|
||||
|
||||
sprintf(user, fNameTC->Text());
|
||||
sprintf(pass, fPassTC->Text());
|
||||
*keep = fKeepUsingCB->Value() == B_CONTROL_ON;
|
||||
|
||||
Quit();
|
||||
return fCancelled;
|
||||
}
|
||||
|
||||
// Cancel
|
||||
void
|
||||
AuthenticationPanel::Cancel()
|
||||
{
|
||||
fCancelled = true;
|
||||
// release_sem(fExitSem);
|
||||
|
||||
Panel::Cancel();
|
||||
}
|
||||
|
||||
|
||||
// _CalculateFrame
|
||||
BRect
|
||||
AuthenticationPanel::_CalculateFrame(BRect frame)
|
||||
{
|
||||
BScreen screen(B_MAIN_SCREEN_ID);
|
||||
BRect screenFrame = screen.Frame();
|
||||
if (!screenFrame.Contains(frame)) {
|
||||
float width = frame.Width();
|
||||
float height = frame.Height();
|
||||
BPoint center;
|
||||
center.x = screenFrame.left + screenFrame.Width() / 2.0;
|
||||
center.y = screenFrame.top + screenFrame.Height() / 4.0;
|
||||
frame.left = center.x - width / 2.0;
|
||||
frame.right = frame.left + width;
|
||||
frame.top = center.y - height / 2.0;
|
||||
frame.bottom = frame.top + height;
|
||||
}
|
||||
return frame;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
// AuthenticationPanel.h
|
||||
|
||||
#ifndef AUTHENTICATION_PANEL_H
|
||||
#define AUTHENTICATION_PANEL_H
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
class BCheckBox;
|
||||
class BTextControl;
|
||||
|
||||
class AuthenticationPanel : public Panel {
|
||||
public:
|
||||
AuthenticationPanel(BRect frame = BRect(-1000.0, -1000.0, -900.0, -900.0));
|
||||
virtual ~AuthenticationPanel();
|
||||
|
||||
virtual bool QuitRequested();
|
||||
|
||||
virtual void MessageReceived(BMessage *message);
|
||||
|
||||
// AuthenticationPanel
|
||||
bool GetAuthentication(const char* server,
|
||||
const char* share,
|
||||
const char* previousUser,
|
||||
const char* previousPass,
|
||||
bool previousKeep,
|
||||
bool badPassword,
|
||||
char* user,
|
||||
char* pass,
|
||||
bool* askAgain);
|
||||
|
||||
virtual void Cancel();
|
||||
|
||||
private:
|
||||
BRect _CalculateFrame(BRect frame);
|
||||
|
||||
|
||||
BTextControl* fNameTC;
|
||||
BTextControl* fPassTC;
|
||||
BCheckBox* fKeepUsingCB;
|
||||
|
||||
BButton* fOkB;
|
||||
BButton* fCancelB;
|
||||
|
||||
bool fCancelled;
|
||||
|
||||
sem_id fExitSem;
|
||||
};
|
||||
|
||||
#endif // AUTHENTICATION_PANEL_H
|
@ -0,0 +1,461 @@
|
||||
// AuthenticationServer.cpp
|
||||
|
||||
#include "AuthenticationServer.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <HashMap.h>
|
||||
#include <HashString.h>
|
||||
#include <util/KMessage.h>
|
||||
|
||||
#include "AuthenticationPanel.h"
|
||||
#include "AuthenticationServerDefs.h"
|
||||
#include "DebugSupport.h"
|
||||
#include "TaskManager.h"
|
||||
|
||||
|
||||
// Authentication
|
||||
class AuthenticationServer::Authentication {
|
||||
public:
|
||||
Authentication()
|
||||
: fUser(),
|
||||
fPassword()
|
||||
{
|
||||
}
|
||||
|
||||
Authentication(const char* user, const char* password)
|
||||
: fUser(user),
|
||||
fPassword(password)
|
||||
{
|
||||
}
|
||||
|
||||
status_t SetTo(const char* user, const char* password)
|
||||
{
|
||||
if (fUser.SetTo(user) && fPassword.SetTo(password))
|
||||
return B_OK;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return (fUser.GetLength() > 0);
|
||||
}
|
||||
|
||||
const char* GetUser() const
|
||||
{
|
||||
return fUser.GetString();
|
||||
}
|
||||
|
||||
const char* GetPassword() const
|
||||
{
|
||||
return fPassword.GetString();
|
||||
}
|
||||
|
||||
private:
|
||||
HashString fUser;
|
||||
HashString fPassword;
|
||||
};
|
||||
|
||||
// ServerKey
|
||||
class AuthenticationServer::ServerKey {
|
||||
public:
|
||||
ServerKey()
|
||||
: fContext(),
|
||||
fServer()
|
||||
{
|
||||
}
|
||||
|
||||
ServerKey(const char* context, const char* server)
|
||||
: fContext(context),
|
||||
fServer(server)
|
||||
{
|
||||
}
|
||||
|
||||
ServerKey(const ServerKey& other)
|
||||
: fContext(other.fContext),
|
||||
fServer(other.fServer)
|
||||
{
|
||||
}
|
||||
|
||||
uint32 GetHashCode() const
|
||||
{
|
||||
return fContext.GetHashCode() * 17 + fServer.GetHashCode();
|
||||
}
|
||||
|
||||
ServerKey& operator=(const ServerKey& other)
|
||||
{
|
||||
fContext = other.fContext;
|
||||
fServer = other.fServer;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const ServerKey& other) const
|
||||
{
|
||||
return (fContext == other.fContext && fServer == other.fServer);
|
||||
}
|
||||
|
||||
bool operator!=(const ServerKey& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
HashString fContext;
|
||||
HashString fServer;
|
||||
};
|
||||
|
||||
// ServerEntry
|
||||
class AuthenticationServer::ServerEntry {
|
||||
public:
|
||||
ServerEntry()
|
||||
: fDefaultAuthentication(),
|
||||
fUseDefaultAuthentication(false)
|
||||
{
|
||||
}
|
||||
|
||||
~ServerEntry()
|
||||
{
|
||||
// delete the authentications
|
||||
for (AuthenticationMap::Iterator it = fAuthentications.GetIterator();
|
||||
it.HasNext();) {
|
||||
delete it.Next().value;
|
||||
}
|
||||
}
|
||||
|
||||
void SetUseDefaultAuthentication(bool useDefaultAuthentication)
|
||||
{
|
||||
fUseDefaultAuthentication = useDefaultAuthentication;
|
||||
}
|
||||
|
||||
bool UseDefaultAuthentication() const
|
||||
{
|
||||
return fUseDefaultAuthentication;
|
||||
}
|
||||
|
||||
status_t SetDefaultAuthentication(const char* user, const char* password)
|
||||
{
|
||||
return fDefaultAuthentication.SetTo(user, password);
|
||||
}
|
||||
|
||||
const Authentication& GetDefaultAuthentication() const
|
||||
{
|
||||
return fDefaultAuthentication;
|
||||
}
|
||||
|
||||
status_t SetAuthentication(const char* share, const char* user,
|
||||
const char* password)
|
||||
{
|
||||
// check, if an entry already exists for the share -- if it does,
|
||||
// just set it
|
||||
Authentication* authentication = fAuthentications.Get(share);
|
||||
if (authentication)
|
||||
return authentication->SetTo(user, password);
|
||||
// the entry does not exist yet: create and add a new one
|
||||
authentication = new(std::nothrow) Authentication;
|
||||
if (!authentication)
|
||||
return B_NO_MEMORY;
|
||||
status_t error = authentication->SetTo(user, password);
|
||||
if (error == B_OK)
|
||||
error = fAuthentications.Put(share, authentication);
|
||||
if (error != B_OK)
|
||||
delete authentication;
|
||||
return error;
|
||||
}
|
||||
|
||||
Authentication* GetAuthentication(const char* share) const
|
||||
{
|
||||
return fAuthentications.Get(share);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef HashMap<HashString, Authentication*> AuthenticationMap;
|
||||
|
||||
Authentication fDefaultAuthentication;
|
||||
bool fUseDefaultAuthentication;
|
||||
AuthenticationMap fAuthentications;
|
||||
};
|
||||
|
||||
// ServerEntryMap
|
||||
struct AuthenticationServer::ServerEntryMap
|
||||
: HashMap<ServerKey, ServerEntry*> {
|
||||
};
|
||||
|
||||
// UserDialogTask
|
||||
class AuthenticationServer::UserDialogTask : public Task {
|
||||
public:
|
||||
UserDialogTask(AuthenticationServer* authenticationServer,
|
||||
const char* context, const char* server, const char* share,
|
||||
bool badPassword, port_id replyPort,
|
||||
int32 replyToken)
|
||||
: Task("user dialog task"),
|
||||
fAuthenticationServer(authenticationServer),
|
||||
fContext(context),
|
||||
fServer(server),
|
||||
fShare(share),
|
||||
fBadPassword(badPassword),
|
||||
fReplyPort(replyPort),
|
||||
fReplyToken(replyToken),
|
||||
fPanel(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
virtual status_t Execute()
|
||||
{
|
||||
// open the panel
|
||||
char user[B_OS_NAME_LENGTH];
|
||||
char password[B_OS_NAME_LENGTH];
|
||||
bool keep = true;
|
||||
fPanel = new(std::nothrow) AuthenticationPanel();
|
||||
status_t error = (fPanel ? B_OK : B_NO_MEMORY);
|
||||
bool cancelled = false;
|
||||
HashString defaultUser;
|
||||
HashString defaultPassword;
|
||||
fAuthenticationServer->_GetAuthentication(fContext.GetString(),
|
||||
fServer.GetString(), NULL, &defaultUser, &defaultPassword);
|
||||
if (error == B_OK) {
|
||||
cancelled = fPanel->GetAuthentication(fServer.GetString(),
|
||||
fShare.GetString(), defaultUser.GetString(),
|
||||
defaultPassword.GetString(), false, fBadPassword, user,
|
||||
password, &keep);
|
||||
}
|
||||
fPanel = NULL;
|
||||
// send the reply
|
||||
if (error != B_OK) {
|
||||
fAuthenticationServer->_SendRequestReply(fReplyPort, fReplyToken,
|
||||
error, true, NULL, NULL);
|
||||
} else if (cancelled) {
|
||||
fAuthenticationServer->_SendRequestReply(fReplyPort, fReplyToken,
|
||||
B_OK, true, NULL, NULL);
|
||||
} else {
|
||||
fAuthenticationServer->_AddAuthentication(fContext.GetString(),
|
||||
fServer.GetString(), fShare.GetString(), user, password,
|
||||
keep);
|
||||
fAuthenticationServer->_SendRequestReply(fReplyPort, fReplyToken,
|
||||
B_OK, false, user, password);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
virtual void Stop()
|
||||
{
|
||||
if (fPanel)
|
||||
fPanel->Cancel();
|
||||
}
|
||||
|
||||
private:
|
||||
AuthenticationServer* fAuthenticationServer;
|
||||
HashString fContext;
|
||||
HashString fServer;
|
||||
HashString fShare;
|
||||
bool fBadPassword;
|
||||
port_id fReplyPort;
|
||||
int32 fReplyToken;
|
||||
AuthenticationPanel* fPanel;
|
||||
};
|
||||
|
||||
|
||||
// constructor
|
||||
AuthenticationServer::AuthenticationServer()
|
||||
: BApplication("application/x-vnd.bonefish.authentification-server"),
|
||||
fLock(),
|
||||
fRequestPort(-1),
|
||||
fRequestThread(-1),
|
||||
fServerEntries(NULL),
|
||||
fTerminating(false)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
AuthenticationServer::~AuthenticationServer()
|
||||
{
|
||||
fTerminating = true;
|
||||
// terminate the request thread
|
||||
if (fRequestPort >= 0)
|
||||
delete_port(fRequestPort);
|
||||
if (fRequestThread >= 0) {
|
||||
int32 result;
|
||||
wait_for_thread(fRequestPort, &result);
|
||||
}
|
||||
// delete the server entries
|
||||
for (ServerEntryMap::Iterator it = fServerEntries->GetIterator();
|
||||
it.HasNext();) {
|
||||
delete it.Next().value;
|
||||
}
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
AuthenticationServer::Init()
|
||||
{
|
||||
// create the server entry map
|
||||
fServerEntries = new(std::nothrow) ServerEntryMap;
|
||||
if (!fServerEntries)
|
||||
return B_NO_MEMORY;
|
||||
status_t error = fServerEntries->InitCheck();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
// create the request port
|
||||
fRequestPort = create_port(10, kAuthenticationServerPortName);
|
||||
if (fRequestPort < 0)
|
||||
return fRequestPort;
|
||||
// spawn the request thread
|
||||
fRequestThread = spawn_thread(&_RequestThreadEntry, "request thread",
|
||||
B_NORMAL_PRIORITY, this);
|
||||
if (fRequestThread < 0)
|
||||
return fRequestThread;
|
||||
resume_thread(fRequestThread);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// _RequestThreadEntry
|
||||
int32
|
||||
AuthenticationServer::_RequestThreadEntry(void* data)
|
||||
{
|
||||
return ((AuthenticationServer*)data)->_RequestThread();
|
||||
}
|
||||
|
||||
// _RequestThread
|
||||
int32
|
||||
AuthenticationServer::_RequestThread()
|
||||
{
|
||||
TaskManager taskManager;
|
||||
while (!fTerminating) {
|
||||
taskManager.RemoveDoneTasks();
|
||||
// read the request
|
||||
KMessage request;
|
||||
status_t error = request.ReceiveFrom(fRequestPort);
|
||||
if (error != B_OK)
|
||||
continue;
|
||||
// get the parameters
|
||||
const char* context = NULL;
|
||||
const char* server = NULL;
|
||||
const char* share = NULL;
|
||||
bool badPassword = true;
|
||||
request.FindString("context", &context);
|
||||
request.FindString("server", &server);
|
||||
request.FindString("share", &share);
|
||||
request.FindBool("badPassword", &badPassword);
|
||||
if (!context || !server || !share)
|
||||
continue;
|
||||
HashString foundUser;
|
||||
HashString foundPassword;
|
||||
if (!badPassword && _GetAuthentication(context, server, share,
|
||||
&foundUser, &foundPassword)) {
|
||||
_SendRequestReply(request.ReplyPort(), request.ReplyToken(),
|
||||
error, false, foundUser.GetString(), foundPassword.GetString());
|
||||
} else {
|
||||
// we need to ask the user: create a task that does it
|
||||
UserDialogTask* task = new(std::nothrow) UserDialogTask(this,
|
||||
context, server, share, badPassword, request.ReplyPort(),
|
||||
request.ReplyToken());
|
||||
if (!task) {
|
||||
ERROR("AuthenticationServer::_RequestThread(): ERROR: "
|
||||
"failed to allocate ");
|
||||
continue;
|
||||
}
|
||||
status_t error = taskManager.RunTask(task);
|
||||
if (error != B_OK) {
|
||||
ERROR("AuthenticationServer::_RequestThread(): Failed to "
|
||||
"start server info task: %s\n", strerror(error));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// _GetAuthentication
|
||||
/*!
|
||||
If share is NULL, the default authentication for the server is returned.
|
||||
*/
|
||||
bool
|
||||
AuthenticationServer::_GetAuthentication(const char* context,
|
||||
const char* server, const char* share, HashString* user,
|
||||
HashString* password)
|
||||
{
|
||||
if (!context || !server || !user || !password)
|
||||
return B_BAD_VALUE;
|
||||
// get the server entry
|
||||
AutoLocker<BLocker> _(fLock);
|
||||
ServerKey key(context, server);
|
||||
ServerEntry* serverEntry = fServerEntries->Get(key);
|
||||
if (!serverEntry)
|
||||
return false;
|
||||
// get the authentication
|
||||
const Authentication* authentication = NULL;
|
||||
if (share) {
|
||||
serverEntry->GetAuthentication(share);
|
||||
if (!authentication && serverEntry->UseDefaultAuthentication())
|
||||
authentication = &serverEntry->GetDefaultAuthentication();
|
||||
} else
|
||||
authentication = &serverEntry->GetDefaultAuthentication();
|
||||
if (!authentication || !authentication->IsValid())
|
||||
return false;
|
||||
return (user->SetTo(authentication->GetUser())
|
||||
&& password->SetTo(authentication->GetPassword()));
|
||||
}
|
||||
|
||||
// _AddAuthentication
|
||||
status_t
|
||||
AuthenticationServer::_AddAuthentication(const char* context,
|
||||
const char* server, const char* share, const char* user,
|
||||
const char* password, bool makeDefault)
|
||||
{
|
||||
AutoLocker<BLocker> _(fLock);
|
||||
ServerKey key(context, server);
|
||||
// get the server entry
|
||||
ServerEntry* serverEntry = fServerEntries->Get(key);
|
||||
if (!serverEntry) {
|
||||
// server entry does not exist yet: create a new one
|
||||
serverEntry = new(std::nothrow) ServerEntry;
|
||||
if (!serverEntry)
|
||||
return B_NO_MEMORY;
|
||||
status_t error = fServerEntries->Put(key, serverEntry);
|
||||
if (error != B_OK) {
|
||||
delete serverEntry;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
// put the authentication
|
||||
status_t error = serverEntry->SetAuthentication(share, user, password);
|
||||
if (error == B_OK) {
|
||||
if (makeDefault || !serverEntry->UseDefaultAuthentication())
|
||||
serverEntry->SetDefaultAuthentication(user, password);
|
||||
if (makeDefault)
|
||||
serverEntry->SetUseDefaultAuthentication(true);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// _SendRequestReply
|
||||
status_t
|
||||
AuthenticationServer::_SendRequestReply(port_id port, int32 token,
|
||||
status_t error, bool cancelled, const char* user, const char* password)
|
||||
{
|
||||
// prepare the reply
|
||||
KMessage reply;
|
||||
reply.AddInt32("error", error);
|
||||
if (error == B_OK) {
|
||||
reply.AddBool("cancelled", cancelled);
|
||||
if (!cancelled) {
|
||||
reply.AddString("user", user);
|
||||
reply.AddString("password", password);
|
||||
}
|
||||
}
|
||||
// send the reply
|
||||
return reply.SendTo(port, token);
|
||||
}
|
||||
|
||||
|
||||
// main
|
||||
int
|
||||
main()
|
||||
{
|
||||
AuthenticationServer app;
|
||||
status_t error = app.Init();
|
||||
if (error != B_OK)
|
||||
return 1;
|
||||
app.Run();
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
// AuthenticationServer.h
|
||||
|
||||
#ifndef NETFS_AUTHENTICATION_SERVER_H
|
||||
#define NETFS_AUTHENTICATION_SERVER_H
|
||||
|
||||
#include <Application.h>
|
||||
#include <Locker.h>
|
||||
|
||||
#include "HashString.h"
|
||||
|
||||
class AuthenticationServer : public BApplication {
|
||||
public:
|
||||
AuthenticationServer();
|
||||
~AuthenticationServer();
|
||||
|
||||
status_t Init();
|
||||
private:
|
||||
static int32 _RequestThreadEntry(void* data);
|
||||
int32 _RequestThread();
|
||||
|
||||
bool _GetAuthentication(const char* context,
|
||||
const char* server, const char* share,
|
||||
HashString* user, HashString* password);
|
||||
status_t _AddAuthentication(const char* context,
|
||||
const char* server, const char* share,
|
||||
const char* user, const char* password,
|
||||
bool makeDefault);
|
||||
status_t _SendRequestReply(port_id port, int32 token,
|
||||
status_t error, bool cancelled,
|
||||
const char* user, const char* password);
|
||||
|
||||
private:
|
||||
class Authentication;
|
||||
class ServerKey;
|
||||
class ServerEntry;
|
||||
class ServerEntryMap;
|
||||
struct AuthenticationRequest;
|
||||
class UserDialogTask;
|
||||
friend class UserDialogTask;
|
||||
|
||||
BLocker fLock;
|
||||
port_id fRequestPort;
|
||||
thread_id fRequestThread;
|
||||
ServerEntryMap* fServerEntries;
|
||||
bool fTerminating;
|
||||
};
|
||||
|
||||
#endif // NETFS_AUTHENTICATION_SERVER_H
|
@ -0,0 +1,24 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel file_systems netfs authentication_server ;
|
||||
|
||||
UsePrivateHeaders shared ;
|
||||
UsePrivateKernelHeaders ;
|
||||
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) headers authentication_server ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) headers shared ] ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) shared ] ;
|
||||
|
||||
DEFINES += USER=1 ;
|
||||
DEFINES += DEBUG_APP="\\\"AuthenticationServer\\\"" ;
|
||||
|
||||
Application AuthenticationServer
|
||||
: DebugSupport.cpp
|
||||
|
||||
AuthenticationServerDefs.cpp
|
||||
TaskManager.cpp
|
||||
|
||||
AuthenticationPanel.cpp
|
||||
AuthenticationServer.cpp
|
||||
Panel.cpp
|
||||
: be $(TARGET_LIBSUPC++) libshared.a
|
||||
;
|
@ -0,0 +1,80 @@
|
||||
// Panel.cpp
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <InterfaceDefs.h>
|
||||
#include <Message.h>
|
||||
#include <MessageFilter.h>
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
class EscapeFilter : public BMessageFilter {
|
||||
public:
|
||||
EscapeFilter(Panel* target)
|
||||
: BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
|
||||
fPanel(target)
|
||||
{
|
||||
}
|
||||
virtual ~EscapeFilter()
|
||||
{
|
||||
}
|
||||
virtual filter_result Filter(BMessage* message, BHandler** target)
|
||||
{
|
||||
filter_result result = B_DISPATCH_MESSAGE;
|
||||
switch (message->what) {
|
||||
case B_KEY_DOWN:
|
||||
case B_UNMAPPED_KEY_DOWN: {
|
||||
uint32 key;
|
||||
if (message->FindInt32("raw_char", (int32*)&key) >= B_OK) {
|
||||
if (key == B_ESCAPE) {
|
||||
result = B_SKIP_MESSAGE;
|
||||
fPanel->Cancel();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
Panel* fPanel;
|
||||
};
|
||||
|
||||
// constructor
|
||||
Panel::Panel(BRect frame, const char* title,
|
||||
window_type type, uint32 flags,
|
||||
uint32 workspace)
|
||||
: BWindow(frame, title, type, flags, workspace)
|
||||
{
|
||||
_InstallFilter();
|
||||
}
|
||||
|
||||
// constructor
|
||||
Panel::Panel(BRect frame, const char* title,
|
||||
window_look look, window_feel feel,
|
||||
uint32 flags, uint32 workspace)
|
||||
: BWindow(frame, title, look, feel, flags, workspace)
|
||||
{
|
||||
_InstallFilter();
|
||||
}
|
||||
|
||||
// destructor
|
||||
Panel::~Panel()
|
||||
{
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
Panel::Cancel()
|
||||
{
|
||||
PostMessage(B_QUIT_REQUESTED);
|
||||
}
|
||||
|
||||
// _InstallFilter
|
||||
void
|
||||
Panel::_InstallFilter()
|
||||
{
|
||||
AddCommonFilter(new EscapeFilter(this));
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
// Panel.h
|
||||
|
||||
#ifndef PANEL_H
|
||||
#define PANEL_H
|
||||
|
||||
#include <Window.h>
|
||||
|
||||
class Panel : public BWindow {
|
||||
public:
|
||||
Panel(BRect frame,
|
||||
const char* title,
|
||||
window_type type,
|
||||
uint32 flags,
|
||||
uint32 workspace = B_CURRENT_WORKSPACE);
|
||||
Panel(BRect frame,
|
||||
const char* title,
|
||||
window_look look,
|
||||
window_feel feel,
|
||||
uint32 flags,
|
||||
uint32 workspace = B_CURRENT_WORKSPACE);
|
||||
virtual ~Panel();
|
||||
|
||||
// Panel
|
||||
virtual void Cancel();
|
||||
|
||||
private:
|
||||
void _InstallFilter();
|
||||
|
||||
};
|
||||
|
||||
#endif // PANEL_H
|
@ -0,0 +1,99 @@
|
||||
// AuthenticationServer.cpp
|
||||
|
||||
#include "AuthenticationServer.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <util/KMessage.h>
|
||||
|
||||
#include "AuthenticationServerDefs.h"
|
||||
#include "Compatibility.h"
|
||||
|
||||
// constructor
|
||||
AuthenticationServer::AuthenticationServer()
|
||||
: fServerPort(-1)
|
||||
{
|
||||
fServerPort = find_port(kAuthenticationServerPortName);
|
||||
}
|
||||
|
||||
// destructor
|
||||
AuthenticationServer::~AuthenticationServer()
|
||||
{
|
||||
}
|
||||
|
||||
// InitCheck
|
||||
status_t
|
||||
AuthenticationServer::InitCheck() const
|
||||
{
|
||||
return (fServerPort >= 0 ? B_OK : fServerPort);
|
||||
}
|
||||
|
||||
// GetAuthentication
|
||||
status_t
|
||||
AuthenticationServer::GetAuthentication(const char* context, const char* server,
|
||||
const char* share, uid_t uid, bool badPassword,
|
||||
bool* _cancelled, char* _foundUser, int32 foundUserSize,
|
||||
char* _foundPassword, int32 foundPasswordSize)
|
||||
{
|
||||
// check parameters/initialization
|
||||
if (!context || !server || !share || !_foundPassword)
|
||||
return B_BAD_VALUE;
|
||||
if (InitCheck() != B_OK)
|
||||
return InitCheck();
|
||||
// prepare the request
|
||||
KMessage request;
|
||||
status_t error = request.AddInt32("uid", uid);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
error = request.AddString("context", context);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
error = request.AddString("server", server);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
error = request.AddString("share", share);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
error = request.AddBool("badPassword", badPassword);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
// send the request
|
||||
KMessage reply;
|
||||
error = request.SendTo(fServerPort, -1, &reply);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
// process the reply
|
||||
// error
|
||||
if (reply.FindInt32("error", &error) != B_OK)
|
||||
return B_ERROR;
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
// cancelled
|
||||
bool cancelled = false;
|
||||
if (reply.FindBool("cancelled", &cancelled) != B_OK)
|
||||
return B_ERROR;
|
||||
if (_cancelled)
|
||||
*_cancelled = cancelled;
|
||||
if (cancelled)
|
||||
return B_OK;
|
||||
// user/password
|
||||
const char* foundUser = NULL;
|
||||
const char* foundPassword = NULL;
|
||||
if (reply.FindString("user", &foundUser) != B_OK
|
||||
|| reply.FindString("password", &foundPassword) != B_OK) {
|
||||
return B_ERROR;
|
||||
}
|
||||
// set results
|
||||
if (_foundUser) {
|
||||
if (foundUserSize <= (int32)strlen(foundUser))
|
||||
return B_BUFFER_OVERFLOW;
|
||||
strcpy(_foundUser, foundUser);
|
||||
}
|
||||
if (_foundPassword) {
|
||||
if (foundPasswordSize <= (int32)strlen(foundPassword))
|
||||
return B_BUFFER_OVERFLOW;
|
||||
strcpy(_foundPassword, foundPassword);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
// AuthenticationServer.h
|
||||
|
||||
#ifndef NET_FS_AUTHENTICATION_SERVER_H
|
||||
#define NET_FS_AUTHENTICATION_SERVER_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
class AuthenticationServer {
|
||||
public:
|
||||
AuthenticationServer();
|
||||
~AuthenticationServer();
|
||||
|
||||
status_t InitCheck() const;
|
||||
|
||||
status_t GetAuthentication(const char* context,
|
||||
const char* server, const char* share,
|
||||
uid_t uid, bool badPassword,
|
||||
bool* cancelled, char* foundUser,
|
||||
int32 foundUserSize, char* foundPassword,
|
||||
int32 foundPasswordSize);
|
||||
|
||||
private:
|
||||
port_id fServerPort;
|
||||
};
|
||||
|
||||
#endif // NET_FS_AUTHENTICATION_SERVER_H
|
@ -0,0 +1,164 @@
|
||||
// ExtendedServerInfo.cpp
|
||||
|
||||
#include "ExtendedServerInfo.h"
|
||||
#include "ServerInfo.h"
|
||||
|
||||
// constructor
|
||||
ExtendedShareInfo::ExtendedShareInfo()
|
||||
:
|
||||
BReferenceable(true),
|
||||
fShareName()
|
||||
{
|
||||
}
|
||||
|
||||
// SetTo
|
||||
status_t
|
||||
ExtendedShareInfo::SetTo(const ShareInfo* shareInfo)
|
||||
{
|
||||
if (!shareInfo)
|
||||
return B_BAD_VALUE;
|
||||
if (!fShareName.SetTo(shareInfo->GetShareName()))
|
||||
return B_NO_MEMORY;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// GetShareName
|
||||
const char*
|
||||
ExtendedShareInfo::GetShareName() const
|
||||
{
|
||||
return fShareName.GetString();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
ExtendedServerInfo::ExtendedServerInfo(const NetAddress& address)
|
||||
:
|
||||
BReferenceable(true),
|
||||
fAddress(address),
|
||||
fState(0)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ExtendedServerInfo::~ExtendedServerInfo()
|
||||
{
|
||||
int32 count = CountShares();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
ShareInfoAt(i)->RemoveReference();
|
||||
}
|
||||
|
||||
// GetAddress
|
||||
const NetAddress&
|
||||
ExtendedServerInfo::GetAddress() const
|
||||
{
|
||||
return fAddress;
|
||||
}
|
||||
|
||||
// GetServerName
|
||||
const char*
|
||||
ExtendedServerInfo::GetServerName() const
|
||||
{
|
||||
return fServerName.GetString();
|
||||
}
|
||||
|
||||
// GetConnectionMethod
|
||||
const char*
|
||||
ExtendedServerInfo::GetConnectionMethod() const
|
||||
{
|
||||
return fConnectionMethod.GetString();
|
||||
}
|
||||
|
||||
// CountShares
|
||||
int32
|
||||
ExtendedServerInfo::CountShares() const
|
||||
{
|
||||
return fShareInfos.Count();
|
||||
}
|
||||
|
||||
// ShareInfoAt
|
||||
ExtendedShareInfo*
|
||||
ExtendedServerInfo::ShareInfoAt(int32 index) const
|
||||
{
|
||||
if (index < 0 || index >= fShareInfos.Count())
|
||||
return NULL;
|
||||
return fShareInfos.ElementAt(index);
|
||||
}
|
||||
|
||||
// GetShareInfo
|
||||
ExtendedShareInfo*
|
||||
ExtendedServerInfo::GetShareInfo(const char* name)
|
||||
{
|
||||
for (int32 i = 0; ExtendedShareInfo* shareInfo = ShareInfoAt(i); i++) {
|
||||
if (strcmp(shareInfo->GetShareName(), name) == 0)
|
||||
return shareInfo;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// SetTo
|
||||
status_t
|
||||
ExtendedServerInfo::SetTo(ServerInfo* serverInfo)
|
||||
{
|
||||
if (!serverInfo)
|
||||
return B_BAD_VALUE;
|
||||
// set name and connection method
|
||||
const char* name = serverInfo->GetServerName();
|
||||
HashString addressString;
|
||||
if (!name || strlen(name) == 0) {
|
||||
status_t error = fAddress.GetString(&addressString, false);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
name = addressString.GetString();
|
||||
}
|
||||
if (!fServerName.SetTo(name)
|
||||
|| !fConnectionMethod.SetTo(serverInfo->GetConnectionMethod())) {
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
// add the shares
|
||||
int32 shareCount = serverInfo->CountShares();
|
||||
for (int32 i = 0; i < shareCount; i++) {
|
||||
const ShareInfo& shareInfo = serverInfo->ShareInfoAt(i);
|
||||
status_t error = _AddShare(&shareInfo);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// SetState
|
||||
void
|
||||
ExtendedServerInfo::SetState(uint32 state)
|
||||
{
|
||||
fState = state;
|
||||
}
|
||||
|
||||
// GetState
|
||||
uint32
|
||||
ExtendedServerInfo::GetState() const
|
||||
{
|
||||
return fState;
|
||||
}
|
||||
|
||||
// _AddShare
|
||||
status_t
|
||||
ExtendedServerInfo::_AddShare(const ShareInfo* info)
|
||||
{
|
||||
ExtendedShareInfo* extendedInfo = new(std::nothrow) ExtendedShareInfo;
|
||||
if (!extendedInfo)
|
||||
return B_NO_MEMORY;
|
||||
status_t error = extendedInfo->SetTo(info);
|
||||
if (error != B_OK) {
|
||||
delete extendedInfo;
|
||||
return error;
|
||||
}
|
||||
error = fShareInfos.PushBack(extendedInfo);
|
||||
if (error != B_OK) {
|
||||
delete extendedInfo;
|
||||
return error;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -0,0 +1,59 @@
|
||||
// ExtendedServerInfo.h
|
||||
|
||||
#ifndef NET_FS_EXTENDED_SERVER_INFO_H
|
||||
#define NET_FS_EXTENDED_SERVER_INFO_H
|
||||
|
||||
#include <HashString.h>
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "NetAddress.h"
|
||||
#include "Vector.h"
|
||||
|
||||
class ServerInfo;
|
||||
class ShareInfo;
|
||||
|
||||
// ExtendedShareInfo
|
||||
class ExtendedShareInfo : public BReferenceable {
|
||||
public:
|
||||
ExtendedShareInfo();
|
||||
|
||||
status_t SetTo(const ShareInfo* shareInfo);
|
||||
|
||||
const char* GetShareName() const;
|
||||
|
||||
private:
|
||||
HashString fShareName;
|
||||
};
|
||||
|
||||
// ExtendedServerInfo
|
||||
class ExtendedServerInfo : public BReferenceable {
|
||||
public:
|
||||
ExtendedServerInfo(const NetAddress& address);
|
||||
~ExtendedServerInfo();
|
||||
|
||||
const NetAddress& GetAddress() const;
|
||||
const char* GetServerName() const;
|
||||
const char* GetConnectionMethod() const;
|
||||
|
||||
int32 CountShares() const;
|
||||
ExtendedShareInfo* ShareInfoAt(int32 index) const;
|
||||
ExtendedShareInfo* GetShareInfo(const char* name);
|
||||
|
||||
status_t SetTo(ServerInfo* serverInfo);
|
||||
|
||||
void SetState(uint32 state);
|
||||
uint32 GetState() const;
|
||||
// used by the ServerManager only
|
||||
|
||||
private:
|
||||
status_t _AddShare(const ShareInfo* info);
|
||||
|
||||
private:
|
||||
NetAddress fAddress;
|
||||
HashString fServerName;
|
||||
HashString fConnectionMethod;
|
||||
Vector<ExtendedShareInfo*> fShareInfos;
|
||||
uint32 fState;
|
||||
};
|
||||
|
||||
#endif // NET_FS_EXTENDED_SERVER_INFO_H
|
92
src/add-ons/kernel/file_systems/netfs/client/Jamfile
Normal file
92
src/add-ons/kernel/file_systems/netfs/client/Jamfile
Normal file
@ -0,0 +1,92 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel file_systems netfs client ;
|
||||
|
||||
UsePrivateHeaders shared ;
|
||||
UsePrivateKernelHeaders ;
|
||||
|
||||
local userlandFSIncludes = [ FDirName $(HAIKU_TOP) headers private
|
||||
userlandfs ] ;
|
||||
|
||||
SubDirSysHdrs [ FDirName $(userlandFSIncludes) legacy ] ;
|
||||
SubDirSysHdrs [ FDirName $(userlandFSIncludes) public ] ;
|
||||
SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ;
|
||||
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) headers authentication_server ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) headers fs ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) headers shared ] ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) shared ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems
|
||||
userlandfs shared ] ;
|
||||
|
||||
DEFINES += USER=1 ;
|
||||
DEFINES += DEBUG_APP="\\\"netfs\\\"" ;
|
||||
|
||||
# If defined this doesn't remove the local machine from the servers accessible
|
||||
# via netfs. For debugging purposes only.
|
||||
if $(NETFS_ADD_SERVER_LOCALHOST) {
|
||||
DEFINES += ADD_SERVER_LOCALHOST=$(NETFS_ADD_SERVER_LOCALHOST) ;
|
||||
}
|
||||
|
||||
Addon <test>netfs
|
||||
: DebugSupport.cpp
|
||||
# Locker.cpp
|
||||
ObjectTracker.cpp
|
||||
# Referencable.cpp
|
||||
|
||||
AbstractConnection.cpp
|
||||
AttrDirInfo.cpp
|
||||
AuthenticationServerDefs.cpp
|
||||
# Blocker.cpp
|
||||
# BlockerPool.cpp
|
||||
Channel.cpp
|
||||
Connection.cpp
|
||||
ConnectionFactory.cpp
|
||||
EntryInfo.cpp
|
||||
FSObject.cpp
|
||||
InsecureChannel.cpp
|
||||
InsecureConnection.cpp
|
||||
# KMessage.cpp
|
||||
NetAddress.cpp
|
||||
NetFSDefs.cpp
|
||||
NodeInfo.cpp
|
||||
PortChannel.cpp
|
||||
PortConnection.cpp
|
||||
Request.cpp
|
||||
RequestChannel.cpp
|
||||
RequestConnection.cpp
|
||||
RequestDumper.cpp
|
||||
RequestFactory.cpp
|
||||
RequestFlattener.cpp
|
||||
RequestHandler.cpp
|
||||
Requests.cpp
|
||||
RequestUnflattener.cpp
|
||||
ServerInfo.cpp
|
||||
ServerNodeID.cpp
|
||||
TaskManager.cpp
|
||||
ThreadLocal.cpp
|
||||
|
||||
AuthenticationServer.cpp
|
||||
ExtendedServerInfo.cpp
|
||||
netfs.cpp
|
||||
Node.cpp
|
||||
QueryIterator.cpp
|
||||
QueryManager.cpp
|
||||
RootVolume.cpp
|
||||
ServerConnection.cpp
|
||||
ServerConnectionProvider.cpp
|
||||
ServerManager.cpp
|
||||
ServerQueryIterator.cpp
|
||||
ServerVolume.cpp
|
||||
ShareAttrDir.cpp
|
||||
ShareAttrDirIterator.cpp
|
||||
ShareNode.cpp
|
||||
ShareVolume.cpp
|
||||
VirtualDir.cpp
|
||||
VirtualVolume.cpp
|
||||
Volume.cpp
|
||||
VolumeEvent.cpp
|
||||
VolumeManager.cpp
|
||||
|
||||
: be libuserlandfs_beos_kernel.so
|
||||
$(TARGET_NETWORK_LIBS) $(TARGET_LIBSUPC++) libshared.a
|
||||
;
|
31
src/add-ons/kernel/file_systems/netfs/client/Node.cpp
Normal file
31
src/add-ons/kernel/file_systems/netfs/client/Node.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
// Node.cpp
|
||||
|
||||
#include "Node.h"
|
||||
|
||||
// constructor
|
||||
Node::Node(Volume* volume, vnode_id id)
|
||||
: fVolume(volume),
|
||||
fID(id),
|
||||
fKnownToVFS(false)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
Node::~Node()
|
||||
{
|
||||
}
|
||||
|
||||
// SetKnownToVFS
|
||||
void
|
||||
Node::SetKnownToVFS(bool known)
|
||||
{
|
||||
fKnownToVFS = known;
|
||||
}
|
||||
|
||||
// IsKnownToVFS
|
||||
bool
|
||||
Node::IsKnownToVFS() const
|
||||
{
|
||||
return fKnownToVFS;
|
||||
}
|
||||
|
29
src/add-ons/kernel/file_systems/netfs/client/Node.h
Normal file
29
src/add-ons/kernel/file_systems/netfs/client/Node.h
Normal file
@ -0,0 +1,29 @@
|
||||
// Node.h
|
||||
|
||||
#ifndef NET_FS_NODE_H
|
||||
#define NET_FS_NODE_H
|
||||
|
||||
#include <fsproto.h>
|
||||
|
||||
#include "ObjectTracker.h"
|
||||
|
||||
class Volume;
|
||||
|
||||
class Node ONLY_OBJECT_TRACKABLE_BASE_CLASS {
|
||||
public:
|
||||
Node(Volume* volume, vnode_id id);
|
||||
virtual ~Node();
|
||||
|
||||
Volume* GetVolume() const { return fVolume; }
|
||||
vnode_id GetID() const { return fID; }
|
||||
|
||||
void SetKnownToVFS(bool known);
|
||||
bool IsKnownToVFS() const;
|
||||
|
||||
private:
|
||||
Volume* fVolume;
|
||||
vnode_id fID;
|
||||
bool fKnownToVFS;
|
||||
};
|
||||
|
||||
#endif // NET_FS_NODE_H
|
126
src/add-ons/kernel/file_systems/netfs/client/QueryIterator.cpp
Normal file
126
src/add-ons/kernel/file_systems/netfs/client/QueryIterator.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
// QueryIterator.cpp
|
||||
|
||||
#include "QueryIterator.h"
|
||||
|
||||
// constructor
|
||||
QueryIterator::QueryIterator(Volume* volume)
|
||||
:
|
||||
BReferenceable(false),
|
||||
fVolume(volume),
|
||||
fParentIterator(NULL),
|
||||
fVolumeLink()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
QueryIterator::~QueryIterator()
|
||||
{
|
||||
}
|
||||
|
||||
// GetVolume
|
||||
Volume*
|
||||
QueryIterator::GetVolume() const
|
||||
{
|
||||
return fVolume;
|
||||
}
|
||||
|
||||
// SetParentIterator
|
||||
void
|
||||
QueryIterator::SetParentIterator(HierarchicalQueryIterator* parent)
|
||||
{
|
||||
fParentIterator = parent;
|
||||
}
|
||||
|
||||
// GetParentIterator
|
||||
HierarchicalQueryIterator*
|
||||
QueryIterator::GetParentIterator() const
|
||||
{
|
||||
return fParentIterator;
|
||||
}
|
||||
|
||||
// ReadQuery
|
||||
status_t
|
||||
QueryIterator::ReadQuery(struct dirent* buffer, size_t bufferSize, int32 count,
|
||||
int32* countRead, bool* done)
|
||||
{
|
||||
*countRead = 0;
|
||||
*done = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
HierarchicalQueryIterator::HierarchicalQueryIterator(Volume* volume)
|
||||
: QueryIterator(volume),
|
||||
fSubIterators(),
|
||||
fCurrentSubIterator(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
HierarchicalQueryIterator::~HierarchicalQueryIterator()
|
||||
{
|
||||
}
|
||||
|
||||
// GetCurrentSubIterator
|
||||
QueryIterator*
|
||||
HierarchicalQueryIterator::GetCurrentSubIterator() const
|
||||
{
|
||||
return fCurrentSubIterator;
|
||||
}
|
||||
|
||||
// NextSubIterator
|
||||
QueryIterator*
|
||||
HierarchicalQueryIterator::NextSubIterator()
|
||||
{
|
||||
if (fCurrentSubIterator)
|
||||
fCurrentSubIterator = fSubIterators.GetNext(fCurrentSubIterator);
|
||||
return fCurrentSubIterator;
|
||||
}
|
||||
|
||||
// RewindSubIterator
|
||||
void
|
||||
HierarchicalQueryIterator::RewindSubIterator()
|
||||
{
|
||||
fCurrentSubIterator = fSubIterators.First();
|
||||
}
|
||||
|
||||
// AddSubIterator
|
||||
void
|
||||
HierarchicalQueryIterator::AddSubIterator(QueryIterator* subIterator)
|
||||
{
|
||||
if (!subIterator)
|
||||
return;
|
||||
|
||||
fSubIterators.Insert(subIterator);
|
||||
subIterator->SetParentIterator(this);
|
||||
if (!fCurrentSubIterator)
|
||||
fCurrentSubIterator = subIterator;
|
||||
}
|
||||
|
||||
// RemoveSubIterator
|
||||
void
|
||||
HierarchicalQueryIterator::RemoveSubIterator(QueryIterator* subIterator)
|
||||
{
|
||||
if (!subIterator)
|
||||
return;
|
||||
|
||||
if (fCurrentSubIterator == subIterator)
|
||||
NextSubIterator();
|
||||
subIterator->SetParentIterator(NULL);
|
||||
fSubIterators.Remove(subIterator);
|
||||
}
|
||||
|
||||
// RemoveAllSubIterators
|
||||
void
|
||||
HierarchicalQueryIterator::RemoveAllSubIterators(
|
||||
DoublyLinkedList<QueryIterator>& subIterators)
|
||||
{
|
||||
while (QueryIterator* iterator = fSubIterators.First()) {
|
||||
RemoveSubIterator(iterator);
|
||||
subIterators.Insert(iterator);
|
||||
}
|
||||
}
|
||||
|
73
src/add-ons/kernel/file_systems/netfs/client/QueryIterator.h
Normal file
73
src/add-ons/kernel/file_systems/netfs/client/QueryIterator.h
Normal file
@ -0,0 +1,73 @@
|
||||
// QueryIterator.h
|
||||
|
||||
#ifndef NET_FS_QUERY_ITERATOR_H
|
||||
#define NET_FS_QUERY_ITERATOR_H
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
class HierarchicalQueryIterator;
|
||||
class Volume;
|
||||
|
||||
// QueryIterator
|
||||
class QueryIterator : public BReferenceable,
|
||||
public DoublyLinkedListLinkImpl<QueryIterator> {
|
||||
public:
|
||||
QueryIterator(Volume* volume);
|
||||
virtual ~QueryIterator();
|
||||
|
||||
Volume* GetVolume() const;
|
||||
|
||||
void SetParentIterator(
|
||||
HierarchicalQueryIterator* parent);
|
||||
HierarchicalQueryIterator* GetParentIterator() const;
|
||||
|
||||
virtual status_t ReadQuery(struct dirent* buffer,
|
||||
size_t bufferSize, int32 count,
|
||||
int32* countRead, bool* done);
|
||||
|
||||
struct GetVolumeLink;
|
||||
friend struct GetVolumeLink;
|
||||
|
||||
private:
|
||||
Volume* fVolume;
|
||||
HierarchicalQueryIterator* fParentIterator;
|
||||
DoublyLinkedListLink<QueryIterator> fVolumeLink;
|
||||
};
|
||||
|
||||
// HierarchicalQueryIterator
|
||||
class HierarchicalQueryIterator : public QueryIterator {
|
||||
public:
|
||||
HierarchicalQueryIterator(Volume* volume);
|
||||
virtual ~HierarchicalQueryIterator();
|
||||
|
||||
QueryIterator* GetCurrentSubIterator() const;
|
||||
QueryIterator* NextSubIterator();
|
||||
void RewindSubIterator();
|
||||
void AddSubIterator(QueryIterator* subIterator);
|
||||
void RemoveSubIterator(QueryIterator* subIterator);
|
||||
void RemoveAllSubIterators(
|
||||
DoublyLinkedList<QueryIterator>&
|
||||
subIterators);
|
||||
|
||||
private:
|
||||
DoublyLinkedList<QueryIterator> fSubIterators;
|
||||
QueryIterator* fCurrentSubIterator;
|
||||
};
|
||||
|
||||
// GetVolumeLink
|
||||
struct QueryIterator::GetVolumeLink {
|
||||
DoublyLinkedListLink<QueryIterator>* operator()(
|
||||
QueryIterator* iterator) const
|
||||
{
|
||||
return &iterator->fVolumeLink;
|
||||
}
|
||||
|
||||
const DoublyLinkedListLink<QueryIterator>* operator()(
|
||||
const QueryIterator* iterator) const
|
||||
{
|
||||
return &iterator->fVolumeLink;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // NET_FS_QUERY_ITERATOR_H
|
285
src/add-ons/kernel/file_systems/netfs/client/QueryManager.cpp
Normal file
285
src/add-ons/kernel/file_systems/netfs/client/QueryManager.cpp
Normal file
@ -0,0 +1,285 @@
|
||||
// QueryManager.cpp
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <fsproto.h>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
#include <HashMap.h>
|
||||
|
||||
#include "DebugSupport.h"
|
||||
#include "Locker.h"
|
||||
#include "QueryManager.h"
|
||||
#include "Volume.h"
|
||||
#include "VolumeManager.h"
|
||||
|
||||
typedef DoublyLinkedList<QueryIterator, QueryIterator::GetVolumeLink>
|
||||
IteratorList;
|
||||
|
||||
// IteratorMap
|
||||
struct QueryManager::IteratorMap : HashMap<HashKey64<vnode_id>, IteratorList*> {
|
||||
};
|
||||
|
||||
|
||||
// constructor
|
||||
QueryManager::QueryManager(VolumeManager* volumeManager)
|
||||
: fLock("query manager"),
|
||||
fVolumeManager(volumeManager),
|
||||
fIterators(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
QueryManager::~QueryManager()
|
||||
{
|
||||
// delete all iterator lists (there shouldn't be any, though)
|
||||
for (IteratorMap::Iterator it = fIterators->GetIterator(); it.HasNext();) {
|
||||
IteratorList* iteratorList = it.Next().value;
|
||||
delete iteratorList;
|
||||
}
|
||||
delete fIterators;
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
QueryManager::Init()
|
||||
{
|
||||
// check lock
|
||||
if (fLock.Sem() < 0)
|
||||
return fLock.Sem();
|
||||
|
||||
// allocate iterator map
|
||||
fIterators = new(std::nothrow) IteratorMap;
|
||||
if (!fIterators)
|
||||
return B_NO_MEMORY;
|
||||
status_t error = fIterators->InitCheck();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// AddIterator
|
||||
status_t
|
||||
QueryManager::AddIterator(QueryIterator* iterator)
|
||||
{
|
||||
if (!iterator || !iterator->GetVolume())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
AutoLocker<Locker> _(fLock);
|
||||
|
||||
// get the iterator list for the volume
|
||||
vnode_id nodeID = iterator->GetVolume()->GetRootID();
|
||||
IteratorList* iteratorList = fIterators->Get(nodeID);
|
||||
if (!iteratorList) {
|
||||
// no list yet: create one
|
||||
iteratorList = new(std::nothrow) IteratorList;
|
||||
if (!iteratorList)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// add it to the map
|
||||
status_t error = fIterators->Put(nodeID, iteratorList);
|
||||
if (error != B_OK) {
|
||||
delete iteratorList;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// add the iterator
|
||||
iteratorList->Insert(iterator);
|
||||
|
||||
// get a volume reference for the iterator
|
||||
iterator->GetVolume()->AddReference();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// AddSubIterator
|
||||
status_t
|
||||
QueryManager::AddSubIterator(HierarchicalQueryIterator* iterator,
|
||||
QueryIterator* subIterator)
|
||||
{
|
||||
if (!iterator || !subIterator)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
AutoLocker<Locker> _(fLock);
|
||||
if (subIterator->GetVolume()->IsUnmounting())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
iterator->AddSubIterator(subIterator);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// RemoveSubIterator
|
||||
status_t
|
||||
QueryManager::RemoveSubIterator(HierarchicalQueryIterator* iterator,
|
||||
QueryIterator* subIterator)
|
||||
{
|
||||
if (!iterator || !subIterator)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
AutoLocker<Locker> _(fLock);
|
||||
if (subIterator->GetParentIterator() != iterator)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
iterator->RemoveSubIterator(subIterator);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// GetCurrentSubIterator
|
||||
QueryIterator*
|
||||
QueryManager::GetCurrentSubIterator(HierarchicalQueryIterator* iterator)
|
||||
{
|
||||
if (!iterator)
|
||||
return NULL;
|
||||
|
||||
AutoLocker<Locker> _(fLock);
|
||||
QueryIterator* subIterator = iterator->GetCurrentSubIterator();
|
||||
if (subIterator)
|
||||
subIterator->AddReference();
|
||||
return subIterator;
|
||||
}
|
||||
|
||||
// NextSubIterator
|
||||
void
|
||||
QueryManager::NextSubIterator(HierarchicalQueryIterator* iterator,
|
||||
QueryIterator* subIterator)
|
||||
{
|
||||
if (iterator) {
|
||||
AutoLocker<Locker> _(fLock);
|
||||
if (iterator->GetCurrentSubIterator() == subIterator)
|
||||
iterator->NextSubIterator();
|
||||
}
|
||||
}
|
||||
|
||||
// RewindSubIterator
|
||||
void
|
||||
QueryManager::RewindSubIterator(HierarchicalQueryIterator* iterator)
|
||||
{
|
||||
if (iterator) {
|
||||
AutoLocker<Locker> _(fLock);
|
||||
iterator->RewindSubIterator();
|
||||
}
|
||||
}
|
||||
|
||||
// PutIterator
|
||||
void
|
||||
QueryManager::PutIterator(QueryIterator* iterator)
|
||||
{
|
||||
if (!iterator)
|
||||
return;
|
||||
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
if (iterator->RemoveReference()) {
|
||||
// last reference removed: remove the iterator
|
||||
|
||||
// remove its subiterators (if any)
|
||||
DoublyLinkedList<QueryIterator> subIterators;
|
||||
if (HierarchicalQueryIterator* hIterator
|
||||
= dynamic_cast<HierarchicalQueryIterator*>(iterator)) {
|
||||
hIterator->RemoveAllSubIterators(subIterators);
|
||||
}
|
||||
|
||||
// remove from the parent iterator
|
||||
HierarchicalQueryIterator* parentIterator
|
||||
= iterator->GetParentIterator();
|
||||
if (parentIterator)
|
||||
parentIterator->RemoveSubIterator(iterator);
|
||||
|
||||
// remove from the list
|
||||
vnode_id nodeID = iterator->GetVolume()->GetRootID();
|
||||
IteratorList* iteratorList = fIterators->Get(nodeID);
|
||||
if (iteratorList) {
|
||||
iteratorList->Remove(iterator);
|
||||
|
||||
// if the list is empty, remove it completely
|
||||
if (!iteratorList->First()) {
|
||||
fIterators->Remove(nodeID);
|
||||
delete iteratorList;
|
||||
}
|
||||
} else {
|
||||
ERROR("QueryManager::PutIterator(): ERROR: No iterator list "
|
||||
"for volume %p!\n", iterator->GetVolume());
|
||||
}
|
||||
|
||||
// free the iterator and surrender its volume reference
|
||||
Volume* volume = iterator->GetVolume();
|
||||
locker.Unlock();
|
||||
volume->FreeQueryIterator(iterator);
|
||||
volume->PutVolume();
|
||||
|
||||
// put the subiterators
|
||||
while (QueryIterator* subIterator = subIterators.First()) {
|
||||
subIterators.Remove(subIterator);
|
||||
PutIterator(subIterator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VolumeUnmounting
|
||||
//
|
||||
// Removes all subiterators belonging to the volume from their parent iterators
|
||||
// and puts the respective reference.
|
||||
void
|
||||
QueryManager::VolumeUnmounting(Volume* volume)
|
||||
{
|
||||
if (!volume || !volume->IsUnmounting())
|
||||
return;
|
||||
|
||||
vnode_id nodeID = volume->GetRootID();
|
||||
IteratorList iterators;
|
||||
DoublyLinkedList<QueryIterator> subIterators;
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
if (IteratorList* iteratorList = fIterators->Get(nodeID)) {
|
||||
// Unset the parent of all iterators and remove one reference.
|
||||
// If the iterators are unreference, remove them.
|
||||
QueryIterator* iterator = iteratorList->First();
|
||||
while (iterator) {
|
||||
QueryIterator* nextIterator = iteratorList->GetNext(iterator);
|
||||
|
||||
if (iterator->GetParentIterator()) {
|
||||
// remove its subiterators (if any)
|
||||
if (HierarchicalQueryIterator* hIterator
|
||||
= dynamic_cast<HierarchicalQueryIterator*>(iterator)) {
|
||||
hIterator->RemoveAllSubIterators(subIterators);
|
||||
}
|
||||
|
||||
// remove from parent
|
||||
iterator->GetParentIterator()->RemoveSubIterator(iterator);
|
||||
|
||||
// remove reference
|
||||
if (iterator->RemoveReference()) {
|
||||
// no more reference: move to our local list
|
||||
iteratorList->Remove(iterator);
|
||||
iterators.Insert(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
iterator = nextIterator;
|
||||
}
|
||||
|
||||
// if the list is empty now, remove it completely
|
||||
if (!iteratorList->First()) {
|
||||
fIterators->Remove(nodeID);
|
||||
delete iteratorList;
|
||||
}
|
||||
|
||||
// free the iterators we have removed and surrender their volume
|
||||
// references
|
||||
locker.Unlock();
|
||||
while (QueryIterator* iterator = iterators.First()) {
|
||||
iterators.Remove(iterator);
|
||||
volume->FreeQueryIterator(iterator);
|
||||
volume->PutVolume();
|
||||
}
|
||||
|
||||
// put the subiterators
|
||||
while (QueryIterator* subIterator = subIterators.First()) {
|
||||
subIterators.Remove(subIterator);
|
||||
PutIterator(subIterator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
81
src/add-ons/kernel/file_systems/netfs/client/QueryManager.h
Normal file
81
src/add-ons/kernel/file_systems/netfs/client/QueryManager.h
Normal file
@ -0,0 +1,81 @@
|
||||
// QueryManager.h
|
||||
|
||||
#ifndef NET_FS_QUERY_MANAGER_H
|
||||
#define NET_FS_QUERY_MANAGER_H
|
||||
|
||||
#include "Locker.h"
|
||||
#include "QueryIterator.h"
|
||||
|
||||
class Volume;
|
||||
class VolumeManager;
|
||||
|
||||
// QueryManager
|
||||
class QueryManager {
|
||||
public:
|
||||
QueryManager(VolumeManager* volumeManager);
|
||||
~QueryManager();
|
||||
|
||||
status_t Init();
|
||||
|
||||
status_t AddIterator(QueryIterator* iterator);
|
||||
|
||||
status_t AddSubIterator(
|
||||
HierarchicalQueryIterator* iterator,
|
||||
QueryIterator* subIterator);
|
||||
private:
|
||||
status_t RemoveSubIterator(
|
||||
HierarchicalQueryIterator* iterator,
|
||||
QueryIterator* subIterator);
|
||||
public:
|
||||
// TODO: Remove.
|
||||
|
||||
QueryIterator* GetCurrentSubIterator(
|
||||
HierarchicalQueryIterator* iterator);
|
||||
void NextSubIterator(
|
||||
HierarchicalQueryIterator* iterator,
|
||||
QueryIterator* subIterator);
|
||||
private:
|
||||
void RewindSubIterator(
|
||||
HierarchicalQueryIterator* iterator);
|
||||
public:
|
||||
// TODO: Remove.
|
||||
|
||||
void PutIterator(QueryIterator* iterator);
|
||||
|
||||
void VolumeUnmounting(Volume* volume);
|
||||
|
||||
private:
|
||||
struct IteratorMap;
|
||||
|
||||
Locker fLock;
|
||||
VolumeManager* fVolumeManager;
|
||||
IteratorMap* fIterators;
|
||||
};
|
||||
|
||||
// QueryIteratorPutter
|
||||
class QueryIteratorPutter {
|
||||
public:
|
||||
QueryIteratorPutter(QueryManager* manager, QueryIterator* iterator)
|
||||
: fManager(manager),
|
||||
fIterator(iterator)
|
||||
{
|
||||
}
|
||||
|
||||
~QueryIteratorPutter()
|
||||
{
|
||||
if (fManager && fIterator)
|
||||
fManager->PutIterator(fIterator);
|
||||
}
|
||||
|
||||
void Detach()
|
||||
{
|
||||
fManager = NULL;
|
||||
fIterator = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
QueryManager* fManager;
|
||||
QueryIterator* fIterator;
|
||||
};
|
||||
|
||||
#endif // NET_FS_QUERY_MANAGER_H
|
327
src/add-ons/kernel/file_systems/netfs/client/RootVolume.cpp
Normal file
327
src/add-ons/kernel/file_systems/netfs/client/RootVolume.cpp
Normal file
@ -0,0 +1,327 @@
|
||||
// RootVolume.cpp
|
||||
|
||||
#include "RootVolume.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "Compatibility.h"
|
||||
#include "DebugSupport.h"
|
||||
#include "ExtendedServerInfo.h"
|
||||
#include "NetAddress.h"
|
||||
#include "netfs_ioctl.h"
|
||||
#include "ServerVolume.h"
|
||||
#include "TaskManager.h"
|
||||
#include "VolumeManager.h"
|
||||
#include "VolumeSupport.h"
|
||||
|
||||
static const int32 kOptimalIOSize = 64 * 1024;
|
||||
static const char* kFSName = "netfs";
|
||||
|
||||
// constructor
|
||||
RootVolume::RootVolume(VolumeManager* volumeManager)
|
||||
: VirtualVolume(volumeManager)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
RootVolume::~RootVolume()
|
||||
{
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
RootVolume::Init()
|
||||
{
|
||||
status_t error = VirtualVolume::Init("Network");
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create and init the server manager
|
||||
fServerManager = new(std::nothrow) ServerManager(this);
|
||||
if (!fServerManager)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
error = fServerManager->Init();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Uninit
|
||||
void
|
||||
RootVolume::Uninit()
|
||||
{
|
||||
// delete the server manager
|
||||
delete fServerManager;
|
||||
fServerManager = NULL;
|
||||
|
||||
VirtualVolume::Uninit();
|
||||
}
|
||||
|
||||
// PrepareToUnmount
|
||||
void
|
||||
RootVolume::PrepareToUnmount()
|
||||
{
|
||||
VirtualVolume::PrepareToUnmount();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- FS -----
|
||||
|
||||
// Mount
|
||||
status_t
|
||||
RootVolume::Mount(const char* device, uint32 flags, const char* parameters,
|
||||
int32 len)
|
||||
{
|
||||
status_t error = NewVNode(fRootNode->GetID(), fRootNode);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// start the server manager
|
||||
fServerManager->Run();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Unmount
|
||||
status_t
|
||||
RootVolume::Unmount()
|
||||
{
|
||||
Uninit();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Sync
|
||||
status_t
|
||||
RootVolume::Sync()
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// ReadFSStat
|
||||
status_t
|
||||
RootVolume::ReadFSStat(fs_info* info)
|
||||
{
|
||||
info->flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME | B_FS_HAS_ATTR
|
||||
| B_FS_IS_SHARED | B_FS_HAS_QUERY;
|
||||
if (fVolumeManager->GetMountFlags() & B_MOUNT_READ_ONLY)
|
||||
info->flags |= B_FS_IS_READONLY;
|
||||
info->block_size = 1024;
|
||||
info->io_size = kOptimalIOSize;
|
||||
info->total_blocks = 0; // TODO: We could at least fill this in.
|
||||
info->free_blocks = LONGLONG_MAX / info->block_size;
|
||||
// keep the Tracker happy
|
||||
strcpy(info->device_name, "");
|
||||
strcpy(info->volume_name, GetName());
|
||||
strcpy(info->fsh_name, kFSName);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// WriteFSStat
|
||||
status_t
|
||||
RootVolume::WriteFSStat(struct fs_info* info, int32 mask)
|
||||
{
|
||||
// TODO: Allow editing the volume name.
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- files -----
|
||||
|
||||
// IOCtl
|
||||
status_t
|
||||
RootVolume::IOCtl(Node* node, void* cookie, int cmd, void* buffer,
|
||||
size_t bufferSize)
|
||||
{
|
||||
if (node != fRootNode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
switch (cmd) {
|
||||
case NET_FS_IOCTL_ADD_SERVER:
|
||||
{
|
||||
// check the parameters
|
||||
if (!buffer)
|
||||
return B_BAD_VALUE;
|
||||
netfs_ioctl_add_server* params = (netfs_ioctl_add_server*)buffer;
|
||||
int32 serverNameLen = strnlen(params->serverName,
|
||||
sizeof(params->serverName));
|
||||
if (serverNameLen == 0
|
||||
|| serverNameLen == sizeof(params->serverName)) {
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
PRINT(("RootVolume::IOCtl(): NET_FS_IOCTL_ADD_SERVER: `%s'\n",
|
||||
params->serverName));
|
||||
|
||||
// get the server address
|
||||
NetAddress netAddress;
|
||||
NetAddressResolver resolver;
|
||||
status_t error = resolver.GetHostAddress(params->serverName, &netAddress);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// ask the server manager to add the server
|
||||
return fServerManager->AddServer(netAddress);
|
||||
}
|
||||
case NET_FS_IOCTL_REMOVE_SERVER:
|
||||
{
|
||||
// check the parameters
|
||||
if (!buffer)
|
||||
return B_BAD_VALUE;
|
||||
netfs_ioctl_remove_server* params
|
||||
= (netfs_ioctl_remove_server*)buffer;
|
||||
int32 serverNameLen = strnlen(params->serverName,
|
||||
sizeof(params->serverName));
|
||||
if (serverNameLen == 0
|
||||
|| serverNameLen == sizeof(params->serverName)) {
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
PRINT(("RootVolume::IOCtl(): NET_FS_IOCTL_REMOVE_SERVER: `%s'\n",
|
||||
params->serverName));
|
||||
|
||||
// get the server volume
|
||||
ServerVolume* serverVolume = _GetServerVolume(params->serverName);
|
||||
if (!serverVolume)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
VolumePutter volumePutter(serverVolume);
|
||||
|
||||
// ask the server manager to remove the server
|
||||
fServerManager->RemoveServer(serverVolume->GetServerAddress());
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
default:
|
||||
PRINT(("RootVolume::IOCtl(): unknown ioctl: %d\n", cmd));
|
||||
return B_BAD_VALUE;
|
||||
break;
|
||||
}
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// ServerAdded
|
||||
void
|
||||
RootVolume::ServerAdded(ExtendedServerInfo* serverInfo)
|
||||
{
|
||||
PRINT(("RootVolume::ServerAdded(%s)\n", serverInfo->GetServerName()));
|
||||
// check, if the server does already exist
|
||||
ServerVolume* serverVolume = _GetServerVolume(serverInfo->GetAddress());
|
||||
if (serverVolume) {
|
||||
WARN(("RootVolume::ServerAdded(): WARNING: ServerVolume does already "
|
||||
"exist.\n"));
|
||||
serverVolume->PutVolume();
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
|
||||
// get a unique name for the server
|
||||
char serverName[B_FILE_NAME_LENGTH];
|
||||
status_t error = GetUniqueEntryName(serverInfo->GetServerName(),
|
||||
serverName);
|
||||
if (error != B_OK)
|
||||
return;
|
||||
|
||||
// create a server volume
|
||||
serverVolume = new(std::nothrow) ServerVolume(fVolumeManager, serverInfo);
|
||||
if (!serverVolume)
|
||||
return;
|
||||
error = serverVolume->Init(serverName);
|
||||
if (error != B_OK) {
|
||||
delete serverVolume;
|
||||
return;
|
||||
}
|
||||
|
||||
// add the volume to the volume manager
|
||||
error = fVolumeManager->AddVolume(serverVolume);
|
||||
if (error != B_OK) {
|
||||
delete serverVolume;
|
||||
return;
|
||||
}
|
||||
VolumePutter volumePutter(serverVolume);
|
||||
|
||||
// add the volume to us
|
||||
locker.Unlock();
|
||||
error = AddChildVolume(serverVolume);
|
||||
if (error != B_OK) {
|
||||
serverVolume->SetUnmounting(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ServerUpdated
|
||||
void
|
||||
RootVolume::ServerUpdated(ExtendedServerInfo* oldInfo,
|
||||
ExtendedServerInfo* newInfo)
|
||||
{
|
||||
PRINT(("RootVolume::ServerUpdated(%s)\n", newInfo->GetServerName()));
|
||||
// get the volume
|
||||
ServerVolume* serverVolume = _GetServerVolume(newInfo->GetAddress());
|
||||
if (!serverVolume)
|
||||
return;
|
||||
|
||||
// set the new server info
|
||||
VolumePutter _(serverVolume);
|
||||
serverVolume->SetServerInfo(newInfo);
|
||||
}
|
||||
|
||||
// ServerRemoved
|
||||
void
|
||||
RootVolume::ServerRemoved(ExtendedServerInfo* serverInfo)
|
||||
{
|
||||
PRINT(("RootVolume::ServerRemoved(%s)\n", serverInfo->GetServerName()));
|
||||
// get the volume
|
||||
ServerVolume* serverVolume = _GetServerVolume(serverInfo->GetAddress());
|
||||
if (!serverVolume)
|
||||
return;
|
||||
|
||||
// set it to unmounting
|
||||
VolumePutter _(serverVolume);
|
||||
serverVolume->SetUnmounting(true);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _GetServerVolume
|
||||
ServerVolume*
|
||||
RootVolume::_GetServerVolume(const char* name)
|
||||
{
|
||||
Volume* volume = GetChildVolume(name);
|
||||
if (!volume)
|
||||
return NULL;
|
||||
if (ServerVolume* serverVolume = dynamic_cast<ServerVolume*>(volume))
|
||||
return serverVolume;
|
||||
fVolumeManager->PutVolume(volume);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// _GetServerVolume
|
||||
ServerVolume*
|
||||
RootVolume::_GetServerVolume(const NetAddress& address)
|
||||
{
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
|
||||
// init a directory iterator
|
||||
VirtualDirIterator iterator;
|
||||
iterator.SetDirectory(fRootNode, true);
|
||||
|
||||
// iterate through the directory
|
||||
const char* name;
|
||||
Node* node;
|
||||
while (iterator.GetCurrentEntry(&name, &node)) {
|
||||
iterator.NextEntry();
|
||||
ServerVolume* volume = dynamic_cast<ServerVolume*>(node->GetVolume());
|
||||
if (volume && volume->GetServerAddress().GetIP() == address.GetIP()) {
|
||||
return dynamic_cast<ServerVolume*>(
|
||||
fVolumeManager->GetVolume(node->GetID()));
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
50
src/add-ons/kernel/file_systems/netfs/client/RootVolume.h
Normal file
50
src/add-ons/kernel/file_systems/netfs/client/RootVolume.h
Normal file
@ -0,0 +1,50 @@
|
||||
// RootVolume.h
|
||||
|
||||
#ifndef NET_FS_ROOT_VOLUME_H
|
||||
#define NET_FS_ROOT_VOLUME_H
|
||||
|
||||
#include <fsproto.h>
|
||||
|
||||
#include "ServerManager.h"
|
||||
#include "VirtualVolume.h"
|
||||
|
||||
class ServerVolume;
|
||||
class VirtualNode;
|
||||
|
||||
class RootVolume : public VirtualVolume, private ServerManager::Listener {
|
||||
public:
|
||||
RootVolume(VolumeManager* volumeManager);
|
||||
~RootVolume();
|
||||
|
||||
status_t Init();
|
||||
void Uninit();
|
||||
|
||||
virtual void PrepareToUnmount();
|
||||
|
||||
// FS
|
||||
status_t Mount(const char* device, uint32 flags,
|
||||
const char* parameters, int32 len);
|
||||
virtual status_t Unmount();
|
||||
virtual status_t Sync();
|
||||
virtual status_t ReadFSStat(fs_info* info);
|
||||
virtual status_t WriteFSStat(struct fs_info* info, int32 mask);
|
||||
|
||||
// files
|
||||
virtual status_t IOCtl(Node* node, void* cookie, int cmd,
|
||||
void* buffer, size_t bufferSize);
|
||||
|
||||
private:
|
||||
virtual void ServerAdded(ExtendedServerInfo* serverInfo);
|
||||
virtual void ServerUpdated(ExtendedServerInfo* oldInfo,
|
||||
ExtendedServerInfo* newInfo);
|
||||
virtual void ServerRemoved(ExtendedServerInfo* serverInfo);
|
||||
|
||||
|
||||
ServerVolume* _GetServerVolume(const char* name);
|
||||
ServerVolume* _GetServerVolume(const NetAddress& address);
|
||||
|
||||
protected:
|
||||
ServerManager* fServerManager;
|
||||
};
|
||||
|
||||
#endif // NET_FS_ROOT_VOLUME_H
|
@ -0,0 +1,53 @@
|
||||
// SendReceiveRequest.h
|
||||
|
||||
#ifndef NET_FS_SEND_RECEIVE_REQUEST_H
|
||||
#define NET_FS_SEND_RECEIVE_REQUEST_H
|
||||
|
||||
#include "RequestChannel.h"
|
||||
#include "RequestConnection.h"
|
||||
|
||||
|
||||
// error code when disconnected
|
||||
enum {
|
||||
ERROR_NOT_CONNECTED = ENOTCONN
|
||||
};
|
||||
|
||||
// SendRequest
|
||||
template<typename Reply>
|
||||
static
|
||||
status_t
|
||||
SendRequest(RequestConnection* connection, Request* request,
|
||||
Reply** _reply)
|
||||
{
|
||||
Request* reply;
|
||||
status_t error = connection->SendRequest(request, &reply);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
*_reply = dynamic_cast<Reply*>(reply);
|
||||
if (!*_reply) {
|
||||
delete reply;
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// ReceiveRequest
|
||||
template<typename SpecificRequest>
|
||||
static
|
||||
status_t
|
||||
ReceiveRequest(RequestChannel* channel, SpecificRequest** _request)
|
||||
{
|
||||
Request* request;
|
||||
status_t error = channel->ReceiveRequest(&request);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
*_request = dynamic_cast<SpecificRequest*>(request);
|
||||
if (!*_request) {
|
||||
delete request;
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif // NET_FS_SEND_RECEIVE_REQUEST_H
|
@ -0,0 +1,213 @@
|
||||
// ServerConnection.cpp
|
||||
|
||||
#include "ServerConnection.h"
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <ByteOrder.h>
|
||||
#include <HashMap.h>
|
||||
|
||||
#include "Connection.h"
|
||||
#include "ConnectionFactory.h"
|
||||
#include "DebugSupport.h"
|
||||
#include "ExtendedServerInfo.h"
|
||||
#include "RequestConnection.h"
|
||||
#include "ShareVolume.h"
|
||||
#include "VolumeEvent.h"
|
||||
#include "VolumeManager.h"
|
||||
|
||||
// VolumeMap
|
||||
struct ServerConnection::VolumeMap : HashMap<HashKey32<int32>, ShareVolume*> {
|
||||
};
|
||||
|
||||
|
||||
// constructor
|
||||
ServerConnection::ServerConnection(VolumeManager* volumeManager,
|
||||
ExtendedServerInfo* serverInfo)
|
||||
:
|
||||
BReferenceable(true),
|
||||
RequestHandler(),
|
||||
fLock("server connection"),
|
||||
fVolumeManager(volumeManager),
|
||||
fServerInfo(serverInfo),
|
||||
fConnection(NULL),
|
||||
fVolumes(NULL),
|
||||
fConnectionBrokenEvent(NULL),
|
||||
fConnected(false)
|
||||
{
|
||||
if (fServerInfo)
|
||||
fServerInfo->AddReference();
|
||||
}
|
||||
|
||||
// destructor
|
||||
ServerConnection::~ServerConnection()
|
||||
{
|
||||
PRINT(("ServerConnection::~ServerConnection()\n"))
|
||||
Close();
|
||||
delete fConnection;
|
||||
delete fVolumes;
|
||||
if (fConnectionBrokenEvent)
|
||||
fConnectionBrokenEvent->RemoveReference();
|
||||
if (fServerInfo)
|
||||
fServerInfo->RemoveReference();
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
ServerConnection::Init(vnode_id connectionBrokenTarget)
|
||||
{
|
||||
if (!fServerInfo)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
// create a connection broken event
|
||||
fConnectionBrokenEvent
|
||||
= new(std::nothrow) ConnectionBrokenEvent(connectionBrokenTarget);
|
||||
if (!fConnectionBrokenEvent)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// get the server address
|
||||
const char* connectionMethod = fServerInfo->GetConnectionMethod();
|
||||
HashString server;
|
||||
status_t error = fServerInfo->GetAddress().GetString(&server, false);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// create the volume map
|
||||
fVolumes = new(std::nothrow) VolumeMap;
|
||||
if (!fVolumes)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
error = fVolumes->InitCheck();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// establish the connection
|
||||
Connection* connection;
|
||||
ConnectionFactory factory;
|
||||
error = factory.CreateConnection(connectionMethod, server.GetString(),
|
||||
&connection);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// create a request connection
|
||||
fConnection = new(std::nothrow) RequestConnection(connection, this);
|
||||
if (!fConnection) {
|
||||
delete connection;
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
}
|
||||
error = fConnection->Init();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// send an `init connection request'
|
||||
|
||||
// prepare the request
|
||||
InitConnectionRequest request;
|
||||
request.bigEndian = B_HOST_IS_BENDIAN;
|
||||
|
||||
// send the request
|
||||
Request* _reply;
|
||||
error = fConnection->SendRequest(&request, &_reply);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
ObjectDeleter<Request> replyDeleter(_reply);
|
||||
|
||||
// everything OK?
|
||||
InitConnectionReply* reply = dynamic_cast<InitConnectionReply*>(_reply);
|
||||
if (!reply)
|
||||
return B_BAD_DATA;
|
||||
if (reply->error != B_OK)
|
||||
return reply->error;
|
||||
|
||||
fConnected = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Close
|
||||
void
|
||||
ServerConnection::Close()
|
||||
{
|
||||
// mark the connection closed (events won't be delivered anymore)
|
||||
{
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
fConnected = false;
|
||||
}
|
||||
|
||||
if (fConnection)
|
||||
fConnection->Close();
|
||||
}
|
||||
|
||||
// IsConnected
|
||||
bool
|
||||
ServerConnection::IsConnected()
|
||||
{
|
||||
return fConnected;
|
||||
}
|
||||
|
||||
// GetRequestConnection
|
||||
RequestConnection*
|
||||
ServerConnection::GetRequestConnection() const
|
||||
{
|
||||
return fConnection;
|
||||
}
|
||||
|
||||
// AddVolume
|
||||
status_t
|
||||
ServerConnection::AddVolume(ShareVolume* volume)
|
||||
{
|
||||
if (!volume)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
AutoLocker<Locker> _(fLock);
|
||||
return fVolumes->Put(volume->GetID(), volume);
|
||||
}
|
||||
|
||||
// RemoveVolume
|
||||
void
|
||||
ServerConnection::RemoveVolume(ShareVolume* volume)
|
||||
{
|
||||
if (!volume)
|
||||
return;
|
||||
|
||||
AutoLocker<Locker> _(fLock);
|
||||
fVolumes->Remove(volume->GetID());
|
||||
}
|
||||
|
||||
// GetVolume
|
||||
ShareVolume*
|
||||
ServerConnection::GetVolume(int32 volumeID)
|
||||
{
|
||||
AutoLocker<Locker> _(fLock);
|
||||
return fVolumes->Get(volumeID);
|
||||
}
|
||||
|
||||
// VisitConnectionBrokenRequest
|
||||
status_t
|
||||
ServerConnection::VisitConnectionBrokenRequest(ConnectionBrokenRequest* request)
|
||||
{
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
if (fConnected) {
|
||||
fConnected = false;
|
||||
fVolumeManager->SendVolumeEvent(fConnectionBrokenEvent);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// VisitNodeMonitoringRequest
|
||||
status_t
|
||||
ServerConnection::VisitNodeMonitoringRequest(NodeMonitoringRequest* request)
|
||||
{
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
if (fConnected) {
|
||||
if (ShareVolume* volume = GetVolume(request->volumeID)) {
|
||||
if (fVolumeManager->GetVolume(volume->GetRootID())) {
|
||||
locker.Unlock();
|
||||
if (request->opcode == B_DEVICE_UNMOUNTED)
|
||||
volume->SetUnmounting(true);
|
||||
else
|
||||
volume->ProcessNodeMonitoringRequest(request);
|
||||
volume->PutVolume();
|
||||
}
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
// ServerConnection.h
|
||||
|
||||
#ifndef NET_FS_SERVER_CONNECTION_H
|
||||
#define NET_FS_SERVER_CONNECTION_H
|
||||
|
||||
#include <fsproto.h>
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "Locker.h"
|
||||
#include "RequestHandler.h"
|
||||
|
||||
class ConnectionBrokenEvent;
|
||||
class ExtendedServerInfo;
|
||||
class RequestConnection;
|
||||
class ShareVolume;
|
||||
class VolumeManager;
|
||||
|
||||
class ServerConnection : public BReferenceable, private RequestHandler {
|
||||
public:
|
||||
ServerConnection(VolumeManager* volumeManager,
|
||||
ExtendedServerInfo* serverInfo);
|
||||
~ServerConnection();
|
||||
|
||||
status_t Init(vnode_id connectionBrokenTarget);
|
||||
void Close();
|
||||
|
||||
bool IsConnected();
|
||||
|
||||
RequestConnection* GetRequestConnection() const;
|
||||
|
||||
status_t AddVolume(ShareVolume* volume);
|
||||
void RemoveVolume(ShareVolume* volume);
|
||||
ShareVolume* GetVolume(int32 volumeID);
|
||||
|
||||
private:
|
||||
virtual status_t VisitConnectionBrokenRequest(
|
||||
ConnectionBrokenRequest* request);
|
||||
virtual status_t VisitNodeMonitoringRequest(
|
||||
NodeMonitoringRequest* request);
|
||||
|
||||
private:
|
||||
struct VolumeMap;
|
||||
|
||||
Locker fLock;
|
||||
VolumeManager* fVolumeManager;
|
||||
ExtendedServerInfo* fServerInfo;
|
||||
RequestConnection* fConnection;
|
||||
VolumeMap* fVolumes;
|
||||
ConnectionBrokenEvent* fConnectionBrokenEvent;
|
||||
volatile bool fConnected;
|
||||
};
|
||||
|
||||
#endif // NET_FS_SERVER_CONNECTION_H
|
@ -0,0 +1,94 @@
|
||||
// ServerConnectionProvider.cpp
|
||||
|
||||
#include "ServerConnectionProvider.h"
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "ExtendedServerInfo.h"
|
||||
#include "ServerConnection.h"
|
||||
|
||||
// constructor
|
||||
ServerConnectionProvider::ServerConnectionProvider(VolumeManager* volumeManager,
|
||||
ExtendedServerInfo* serverInfo,
|
||||
vnode_id connectionBrokenTarget)
|
||||
:
|
||||
BReferenceable(true),
|
||||
fLock("server connection provider"),
|
||||
fVolumeManager(volumeManager),
|
||||
fServerInfo(serverInfo),
|
||||
fServerConnection(NULL),
|
||||
fConnectionBrokenTarget(connectionBrokenTarget)
|
||||
{
|
||||
if (fServerInfo)
|
||||
fServerInfo->AddReference();
|
||||
}
|
||||
|
||||
// destructor
|
||||
ServerConnectionProvider::~ServerConnectionProvider()
|
||||
{
|
||||
AutoLocker<Locker> _(fLock);
|
||||
if (fServerConnection) {
|
||||
fServerConnection->Close();
|
||||
fServerConnection->RemoveReference();
|
||||
}
|
||||
|
||||
if (fServerInfo)
|
||||
fServerInfo->RemoveReference();
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
ServerConnectionProvider::Init()
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// GetServerConnection
|
||||
status_t
|
||||
ServerConnectionProvider::GetServerConnection(
|
||||
ServerConnection** serverConnection)
|
||||
{
|
||||
AutoLocker<Locker> _(fLock);
|
||||
|
||||
// if there is no server connection yet, create one
|
||||
if (!fServerConnection) {
|
||||
fServerConnection = new(std::nothrow) ServerConnection(fVolumeManager,
|
||||
fServerInfo);
|
||||
if (!fServerConnection)
|
||||
return B_NO_MEMORY;
|
||||
status_t error = fServerConnection->Init(fConnectionBrokenTarget);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!fServerConnection->IsConnected())
|
||||
return B_ERROR;
|
||||
|
||||
fServerConnection->AddReference();
|
||||
*serverConnection = fServerConnection;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// GetExistingServerConnection
|
||||
ServerConnection*
|
||||
ServerConnectionProvider::GetExistingServerConnection()
|
||||
{
|
||||
AutoLocker<Locker> _(fLock);
|
||||
|
||||
// if there is no server connection yet, create one
|
||||
if (!fServerConnection || !fServerConnection->IsConnected())
|
||||
return NULL;
|
||||
|
||||
fServerConnection->AddReference();
|
||||
return fServerConnection;
|
||||
}
|
||||
|
||||
// CloseServerConnection
|
||||
void
|
||||
ServerConnectionProvider::CloseServerConnection()
|
||||
{
|
||||
AutoLocker<Locker> _(fLock);
|
||||
if (fServerConnection)
|
||||
fServerConnection->Close();
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
// ServerConnectionProvider.h
|
||||
|
||||
#ifndef NET_FS_SERVER_CONNECTON_PROVIDER_H
|
||||
#define NET_FS_SERVER_CONNECTON_PROVIDER_H
|
||||
|
||||
#include <fsproto.h>
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "Locker.h"
|
||||
|
||||
class ExtendedServerInfo;
|
||||
class ServerConnection;
|
||||
class VolumeManager;
|
||||
|
||||
class ServerConnectionProvider : public BReferenceable {
|
||||
public:
|
||||
ServerConnectionProvider(
|
||||
VolumeManager* volumeManager,
|
||||
ExtendedServerInfo* serverInfo,
|
||||
vnode_id connectionBrokenTarget);
|
||||
~ServerConnectionProvider();
|
||||
|
||||
status_t Init();
|
||||
|
||||
status_t GetServerConnection(
|
||||
ServerConnection** serverConnection);
|
||||
ServerConnection* GetExistingServerConnection();
|
||||
|
||||
void CloseServerConnection();
|
||||
|
||||
private:
|
||||
Locker fLock;
|
||||
VolumeManager* fVolumeManager;
|
||||
ExtendedServerInfo* fServerInfo;
|
||||
ServerConnection* fServerConnection;
|
||||
vnode_id fConnectionBrokenTarget;
|
||||
};
|
||||
|
||||
#endif // NET_FS_SERVER_CONNECTON_PROVIDER_H
|
589
src/add-ons/kernel/file_systems/netfs/client/ServerManager.cpp
Normal file
589
src/add-ons/kernel/file_systems/netfs/client/ServerManager.cpp
Normal file
@ -0,0 +1,589 @@
|
||||
// ServerManager.cpp
|
||||
|
||||
#include "ServerManager.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAIKU_TARGET_PLATFORM_BEOS
|
||||
# include <socket.h>
|
||||
#else
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <AutoLocker.h>
|
||||
#include <ByteOrder.h>
|
||||
#include <HashMap.h>
|
||||
|
||||
#include "Compatibility.h"
|
||||
#include "DebugSupport.h"
|
||||
#include "ExtendedServerInfo.h"
|
||||
#include "InsecureChannel.h"
|
||||
#include "NetAddress.h"
|
||||
#include "NetFSDefs.h"
|
||||
#include "RequestChannel.h"
|
||||
#include "Requests.h"
|
||||
#include "TaskManager.h"
|
||||
#include "Utils.h"
|
||||
|
||||
// server info states
|
||||
enum {
|
||||
STATE_ADDING,
|
||||
STATE_REMOVING,
|
||||
STATE_UPDATING,
|
||||
STATE_READY,
|
||||
STATE_OBSOLETE
|
||||
};
|
||||
|
||||
|
||||
// ServerInfoMap
|
||||
struct ServerManager::ServerInfoMap : HashMap<NetAddress, ExtendedServerInfo*> {
|
||||
};
|
||||
|
||||
// ServerInfoTask
|
||||
class ServerManager::ServerInfoTask : public Task {
|
||||
public:
|
||||
ServerInfoTask(ServerManager* manager, ExtendedServerInfo* oldServerInfo,
|
||||
ExtendedServerInfo* serverInfo)
|
||||
: Task("server info task"),
|
||||
fServerManager(manager),
|
||||
fOldServerInfo(oldServerInfo),
|
||||
fServerInfo(serverInfo),
|
||||
fFD(-1),
|
||||
fSuccess(false)
|
||||
{
|
||||
if (fServerInfo)
|
||||
fServerInfo->AddReference();
|
||||
}
|
||||
|
||||
virtual ~ServerInfoTask()
|
||||
{
|
||||
Stop();
|
||||
if (!fSuccess) {
|
||||
if (fOldServerInfo)
|
||||
fServerManager->_UpdatingServerFailed(fServerInfo);
|
||||
else
|
||||
fServerManager->_AddingServerFailed(fServerInfo);
|
||||
}
|
||||
if (fServerInfo)
|
||||
fServerInfo->RemoveReference();
|
||||
}
|
||||
|
||||
status_t Init()
|
||||
{
|
||||
// create a socket
|
||||
fFD = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fFD < 0) {
|
||||
ERROR("ServerManager::ServerInfoTask: ERROR: Failed to create "
|
||||
"socket: %s\n", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
virtual status_t Execute()
|
||||
{
|
||||
// connect to the server info port
|
||||
sockaddr_in addr = fServerInfo->GetAddress().GetAddress();
|
||||
addr.sin_port = htons(kDefaultServerInfoPort);
|
||||
if (connect(fFD, (sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
ERROR("ServerManager::ServerInfoTask: ERROR: Failed to connect "
|
||||
"to server info port: %s\n", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
// create a channel
|
||||
InsecureChannel channel(fFD);
|
||||
|
||||
// receive a request
|
||||
RequestChannel requestChannel(&channel);
|
||||
Request* _request;
|
||||
status_t error = requestChannel.ReceiveRequest(&_request);
|
||||
if (error != B_OK) {
|
||||
ERROR("ServerManager::ServerInfoTask: ERROR: Failed to receive "
|
||||
"server info request: %s\n", strerror(errno));
|
||||
return error;
|
||||
}
|
||||
ObjectDeleter<Request> requestDeleter(_request);
|
||||
ServerInfoRequest* request = dynamic_cast<ServerInfoRequest*>(_request);
|
||||
if (!request) {
|
||||
ERROR("ServerManager::ServerInfoTask: ERROR: Received request "
|
||||
"is not a server info request.\n");
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
// get the info
|
||||
error = fServerInfo->SetTo(&request->serverInfo);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// notify the manager
|
||||
if (fOldServerInfo)
|
||||
fServerManager->_ServerUpdated(fServerInfo);
|
||||
else
|
||||
fServerManager->_ServerAdded(fServerInfo);
|
||||
|
||||
fSuccess = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
virtual void Stop()
|
||||
{
|
||||
safe_closesocket(fFD);
|
||||
}
|
||||
|
||||
private:
|
||||
ServerManager* fServerManager;
|
||||
ExtendedServerInfo* fOldServerInfo;
|
||||
ExtendedServerInfo* fServerInfo;
|
||||
vint32 fFD;
|
||||
bool fUpdate;
|
||||
bool fSuccess;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
ServerManager::ServerManager(Listener* listener)
|
||||
: fLock("server manager"),
|
||||
fBroadcastListener(-1),
|
||||
fBroadcastListenerSocket(-1),
|
||||
fListener(listener),
|
||||
fTerminating(false)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ServerManager::~ServerManager()
|
||||
{
|
||||
Uninit();
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
ServerManager::Init()
|
||||
{
|
||||
// create the server info map
|
||||
fServerInfos = new(std::nothrow) ServerInfoMap();
|
||||
if (!fServerInfos)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
status_t error = fServerInfos->InitCheck();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// init the broadcast listener
|
||||
error = _InitBroadcastListener();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Uninit
|
||||
void
|
||||
ServerManager::Uninit()
|
||||
{
|
||||
// stop the broadcast listener
|
||||
fTerminating = true;
|
||||
_TerminateBroadcastListener();
|
||||
|
||||
// remove all server infos
|
||||
AutoLocker<Locker> _(fLock);
|
||||
for (ServerInfoMap::Iterator it = fServerInfos->GetIterator();
|
||||
it.HasNext();) {
|
||||
ExtendedServerInfo* serverInfo = it.Next().value;
|
||||
serverInfo->RemoveReference();
|
||||
}
|
||||
fServerInfos->Clear();
|
||||
}
|
||||
|
||||
// Run
|
||||
void
|
||||
ServerManager::Run()
|
||||
{
|
||||
// start the broadcast listener
|
||||
resume_thread(fBroadcastListener);
|
||||
}
|
||||
|
||||
// GetServerInfo
|
||||
ExtendedServerInfo*
|
||||
ServerManager::GetServerInfo(const NetAddress& address)
|
||||
{
|
||||
AutoLocker<Locker> _(fLock);
|
||||
ExtendedServerInfo* serverInfo = fServerInfos->Get(address);
|
||||
if (!serverInfo
|
||||
|| (serverInfo->GetState() != STATE_READY
|
||||
&& serverInfo->GetState() != STATE_UPDATING)) {
|
||||
return NULL;
|
||||
}
|
||||
serverInfo->AddReference();
|
||||
return serverInfo;
|
||||
}
|
||||
|
||||
// AddServer
|
||||
status_t
|
||||
ServerManager::AddServer(const NetAddress& address)
|
||||
{
|
||||
// check, if the server is already known
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
ExtendedServerInfo* oldInfo = fServerInfos->Get(address);
|
||||
if (oldInfo)
|
||||
return B_OK;
|
||||
|
||||
// create a new server info and add it
|
||||
ExtendedServerInfo* serverInfo
|
||||
= new(std::nothrow) ExtendedServerInfo(address);
|
||||
if (!serverInfo)
|
||||
return B_NO_MEMORY;
|
||||
serverInfo->SetState(STATE_ADDING);
|
||||
Reference<ExtendedServerInfo> serverInfoReference(serverInfo, true);
|
||||
status_t error = fServerInfos->Put(address, serverInfo);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
serverInfo->AddReference();
|
||||
|
||||
// create and execute the task -- it will do what is necessary
|
||||
ServerInfoTask task(this, NULL, serverInfo);
|
||||
error = task.Init();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
locker.Unlock();
|
||||
return task.Execute();
|
||||
}
|
||||
|
||||
// RemoveServer
|
||||
void
|
||||
ServerManager::RemoveServer(const NetAddress& address)
|
||||
{
|
||||
// check, if the server is known at all
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
ExtendedServerInfo* serverInfo = fServerInfos->Get(address);
|
||||
if (!serverInfo)
|
||||
return;
|
||||
|
||||
// If its current state is not STATE_READY, then an info thread is currently
|
||||
// trying to add/update it. We mark the info STATE_REMOVING, which will
|
||||
// remove the info as soon as possible.
|
||||
if (serverInfo->GetState() == STATE_READY) {
|
||||
Reference<ExtendedServerInfo> _(serverInfo);
|
||||
_RemoveServer(serverInfo);
|
||||
locker.Unlock();
|
||||
fListener->ServerRemoved(serverInfo);
|
||||
} else
|
||||
serverInfo->SetState(STATE_REMOVING);
|
||||
}
|
||||
|
||||
// _BroadcastListenerEntry
|
||||
int32
|
||||
ServerManager::_BroadcastListenerEntry(void* data)
|
||||
{
|
||||
return ((ServerManager*)data)->_BroadcastListener();
|
||||
}
|
||||
|
||||
// _BroadcastListener
|
||||
int32
|
||||
ServerManager::_BroadcastListener()
|
||||
{
|
||||
TaskManager taskManager;
|
||||
while (!fTerminating) {
|
||||
taskManager.RemoveDoneTasks();
|
||||
|
||||
// receive
|
||||
sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(kDefaultBroadcastPort);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
socklen_t addrSize = sizeof(addr);
|
||||
BroadcastMessage message;
|
||||
//PRINT(("ServerManager::_BroadcastListener(): recvfrom()...\n"));
|
||||
ssize_t bytesRead = recvfrom(fBroadcastListenerSocket, &message,
|
||||
sizeof(message), 0, (sockaddr*)&addr, &addrSize);
|
||||
if (bytesRead < 0) {
|
||||
PRINT(("ServerManager::_BroadcastListener(): recvfrom() failed: %s\n",
|
||||
strerror(errno)));
|
||||
continue;
|
||||
}
|
||||
|
||||
// check message size, magic, and protocol version
|
||||
if (bytesRead != sizeof(BroadcastMessage)) {
|
||||
PRINT(("ServerManager::_BroadcastListener(): received %ld bytes, but "
|
||||
"it should be %lu\n", bytesRead, sizeof(BroadcastMessage)));
|
||||
continue;
|
||||
}
|
||||
if (message.magic != B_HOST_TO_BENDIAN_INT32(BROADCAST_MESSAGE_MAGIC)) {
|
||||
PRINT(("ServerManager::_BroadcastListener(): message has bad "
|
||||
"magic.\n"));
|
||||
continue;
|
||||
}
|
||||
if (message.protocolVersion
|
||||
!= (int32)B_HOST_TO_BENDIAN_INT32(NETFS_PROTOCOL_VERSION)) {
|
||||
PRINT(("ServerManager::_BroadcastListener(): protocol version "
|
||||
"does not match: %lu vs. %d.\n",
|
||||
B_BENDIAN_TO_HOST_INT32(message.protocolVersion),
|
||||
NETFS_PROTOCOL_VERSION));
|
||||
continue;
|
||||
}
|
||||
|
||||
// check, if the server is local
|
||||
NetAddress netAddress(addr);
|
||||
#ifndef ADD_SERVER_LOCALHOST
|
||||
if (netAddress.IsLocal())
|
||||
continue;
|
||||
#endif // ADD_SERVER_LOCALHOST
|
||||
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
ExtendedServerInfo* oldServerInfo = fServerInfos->Get(netAddress);
|
||||
|
||||
// examine the message
|
||||
switch (B_BENDIAN_TO_HOST_INT32(message.message)) {
|
||||
case BROADCAST_MESSAGE_SERVER_TICK:
|
||||
// PRINT(("ServerManager::_BroadcastListener(): "
|
||||
// "BROADCAST_MESSAGE_SERVER_TICK.\n"));
|
||||
if (oldServerInfo)
|
||||
continue;
|
||||
break;
|
||||
case BROADCAST_MESSAGE_SERVER_UPDATE:
|
||||
// PRINT(("ServerManager::_BroadcastListener(): "
|
||||
// "BROADCAST_MESSAGE_SERVER_UPDATE.\n"));
|
||||
break;
|
||||
case BROADCAST_MESSAGE_CLIENT_HELLO:
|
||||
// PRINT(("ServerManager::_BroadcastListener(): "
|
||||
// "BROADCAST_MESSAGE_CLIENT_HELLO. Ignoring.\n"));
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (oldServerInfo && oldServerInfo->GetState() != STATE_READY)
|
||||
continue;
|
||||
|
||||
// create a new server info and add it
|
||||
ExtendedServerInfo* serverInfo
|
||||
= new(std::nothrow) ExtendedServerInfo(netAddress);
|
||||
if (!serverInfo)
|
||||
return B_NO_MEMORY;
|
||||
serverInfo->SetState(STATE_ADDING);
|
||||
Reference<ExtendedServerInfo> serverInfoReference(serverInfo, true);
|
||||
if (oldServerInfo) {
|
||||
oldServerInfo->SetState(STATE_UPDATING);
|
||||
} else {
|
||||
status_t error = fServerInfos->Put(netAddress, serverInfo);
|
||||
if (error != B_OK)
|
||||
continue;
|
||||
serverInfo->AddReference();
|
||||
}
|
||||
|
||||
// create a task to add/update the server info
|
||||
ServerInfoTask* task = new(std::nothrow) ServerInfoTask(this, oldServerInfo,
|
||||
serverInfo);
|
||||
if (!task) {
|
||||
if (oldServerInfo) {
|
||||
oldServerInfo->SetState(STATE_READY);
|
||||
} else {
|
||||
fServerInfos->Remove(serverInfo->GetAddress());
|
||||
serverInfo->RemoveReference();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// now the task has all info and will call the respective cleanup
|
||||
// method when being deleted
|
||||
if (task->Init() != B_OK) {
|
||||
delete task;
|
||||
continue;
|
||||
}
|
||||
status_t error = taskManager.RunTask(task);
|
||||
if (error != B_OK) {
|
||||
ERROR("ServerManager::_BroadcastListener(): Failed to start server "
|
||||
"info task: %s\n", strerror(error));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// _InitBroadcastListener
|
||||
status_t
|
||||
ServerManager::_InitBroadcastListener()
|
||||
{
|
||||
// create a socket
|
||||
fBroadcastListenerSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fBroadcastListenerSocket < 0)
|
||||
return errno;
|
||||
// bind it to the port
|
||||
sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(kDefaultBroadcastPort);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(fBroadcastListenerSocket, (sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
ERROR("ServerManager::_InitBroadcastListener(): ERROR: bind()ing the "
|
||||
"broadcasting socket failed: %s\n", strerror(errno));
|
||||
safe_closesocket(fBroadcastListenerSocket);
|
||||
return errno;
|
||||
}
|
||||
// spawn the thread
|
||||
#if USER
|
||||
fBroadcastListener = spawn_thread(&_BroadcastListenerEntry,
|
||||
"broadcast listener", B_NORMAL_PRIORITY, this);
|
||||
#else
|
||||
fBroadcastListener = spawn_kernel_thread(&_BroadcastListenerEntry,
|
||||
"broadcast listener", B_NORMAL_PRIORITY, this);
|
||||
#endif
|
||||
if (fBroadcastListener < 0)
|
||||
return fBroadcastListener;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// _TerminateBroadcastListener
|
||||
void
|
||||
ServerManager::_TerminateBroadcastListener()
|
||||
{
|
||||
safe_closesocket(fBroadcastListenerSocket);
|
||||
if (fBroadcastListener >= 0) {
|
||||
int32 result;
|
||||
wait_for_thread(fBroadcastListener, &result);
|
||||
}
|
||||
}
|
||||
|
||||
// _ServerAdded
|
||||
void
|
||||
ServerManager::_ServerAdded(ExtendedServerInfo* serverInfo)
|
||||
{
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
if (fServerInfos->Get(serverInfo->GetAddress()) == serverInfo) {
|
||||
// check whether someone told us to remove the server in the meantime
|
||||
if (serverInfo->GetState() == STATE_REMOVING) {
|
||||
_RemoveServer(serverInfo);
|
||||
if (fListener) {
|
||||
locker.Unlock();
|
||||
fListener->ServerRemoved(serverInfo);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// no, everything is fine: go on...
|
||||
serverInfo->SetState(STATE_READY);
|
||||
if (fListener) {
|
||||
locker.Unlock();
|
||||
fListener->ServerAdded(serverInfo);
|
||||
}
|
||||
} else {
|
||||
WARN("ServerManager::_ServerAdded(%p): WARNING: Unexpected server "
|
||||
"info.\n", serverInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// _ServerUpdated
|
||||
void
|
||||
ServerManager::_ServerUpdated(ExtendedServerInfo* serverInfo)
|
||||
{
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
ExtendedServerInfo* oldInfo = fServerInfos->Get(serverInfo->GetAddress());
|
||||
if (serverInfo != oldInfo) {
|
||||
// check whether someone told us to remove the server in the meantime
|
||||
if (oldInfo->GetState() == STATE_REMOVING) {
|
||||
oldInfo->AddReference();
|
||||
_RemoveServer(oldInfo);
|
||||
if (fListener) {
|
||||
locker.Unlock();
|
||||
fListener->ServerRemoved(oldInfo);
|
||||
}
|
||||
oldInfo->RemoveReference();
|
||||
return;
|
||||
}
|
||||
|
||||
// no, everything is fine: go on...
|
||||
fServerInfos->Put(serverInfo->GetAddress(), serverInfo);
|
||||
serverInfo->AddReference();
|
||||
serverInfo->SetState(STATE_READY);
|
||||
oldInfo->SetState(STATE_OBSOLETE);
|
||||
if (fListener) {
|
||||
locker.Unlock();
|
||||
fListener->ServerUpdated(oldInfo, serverInfo);
|
||||
}
|
||||
oldInfo->RemoveReference();
|
||||
} else {
|
||||
WARN("ServerManager::_ServerUpdated(%p): WARNING: Unexpected server "
|
||||
"info.\n", serverInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// _AddingServerFailed
|
||||
void
|
||||
ServerManager::_AddingServerFailed(ExtendedServerInfo* serverInfo)
|
||||
{
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
if (fServerInfos->Get(serverInfo->GetAddress()) == serverInfo) {
|
||||
bool removing = (serverInfo->GetState() == STATE_REMOVING);
|
||||
fServerInfos->Remove(serverInfo->GetAddress());
|
||||
serverInfo->RemoveReference();
|
||||
serverInfo->SetState(STATE_OBSOLETE);
|
||||
|
||||
// notify the listener, if someone told us in the meantime to remove
|
||||
// the server
|
||||
if (removing) {
|
||||
locker.Unlock();
|
||||
fListener->ServerRemoved(serverInfo);
|
||||
}
|
||||
} else {
|
||||
WARN("ServerManager::_AddingServerFailed(%p): WARNING: Unexpected "
|
||||
"server info.\n", serverInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// _UpdatingServerFailed
|
||||
void
|
||||
ServerManager::_UpdatingServerFailed(ExtendedServerInfo* serverInfo)
|
||||
{
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
ExtendedServerInfo* oldInfo = fServerInfos->Get(serverInfo->GetAddress());
|
||||
if (serverInfo != oldInfo) {
|
||||
// check whether someone told us to remove the server in the meantime
|
||||
if (oldInfo->GetState() == STATE_REMOVING) {
|
||||
oldInfo->AddReference();
|
||||
_RemoveServer(oldInfo);
|
||||
if (fListener) {
|
||||
locker.Unlock();
|
||||
fListener->ServerRemoved(oldInfo);
|
||||
}
|
||||
oldInfo->RemoveReference();
|
||||
serverInfo->SetState(STATE_OBSOLETE);
|
||||
return;
|
||||
}
|
||||
|
||||
// no, everything is fine: go on...
|
||||
serverInfo->SetState(STATE_OBSOLETE);
|
||||
oldInfo->SetState(STATE_READY);
|
||||
} else {
|
||||
WARN("ServerManager::_UpdatingServerFailed(%p): WARNING: Unexpected "
|
||||
"server info.\n", serverInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// _RemoveServer
|
||||
//
|
||||
// fLock must be held.
|
||||
void
|
||||
ServerManager::_RemoveServer(ExtendedServerInfo* serverInfo)
|
||||
{
|
||||
if (!serverInfo)
|
||||
return;
|
||||
|
||||
ExtendedServerInfo* oldInfo = fServerInfos->Get(serverInfo->GetAddress());
|
||||
if (oldInfo) {
|
||||
fServerInfos->Remove(oldInfo->GetAddress());
|
||||
oldInfo->SetState(STATE_OBSOLETE);
|
||||
oldInfo->RemoveReference();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// destructor
|
||||
ServerManager::Listener::~Listener()
|
||||
{
|
||||
}
|
||||
|
70
src/add-ons/kernel/file_systems/netfs/client/ServerManager.h
Normal file
70
src/add-ons/kernel/file_systems/netfs/client/ServerManager.h
Normal file
@ -0,0 +1,70 @@
|
||||
// ServerManager.h
|
||||
|
||||
#ifndef NET_FS_SERVER_MANAGER_H
|
||||
#define NET_FS_SERVER_MANAGER_H
|
||||
|
||||
#include "Locker.h"
|
||||
|
||||
class ExtendedServerInfo;
|
||||
class NetAddress;
|
||||
|
||||
// ServerManager
|
||||
class ServerManager {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
public:
|
||||
ServerManager(Listener* listener);
|
||||
~ServerManager();
|
||||
|
||||
status_t Init();
|
||||
void Uninit();
|
||||
|
||||
void Run();
|
||||
|
||||
ExtendedServerInfo* GetServerInfo(const NetAddress& address);
|
||||
status_t AddServer(const NetAddress& address);
|
||||
void RemoveServer(const NetAddress& address);
|
||||
|
||||
private:
|
||||
struct ServerInfoMap;
|
||||
class ServerInfoTask;
|
||||
friend class ServerInfoTask;
|
||||
|
||||
static int32 _BroadcastListenerEntry(void* data);
|
||||
int32 _BroadcastListener();
|
||||
status_t _InitBroadcastListener();
|
||||
void _TerminateBroadcastListener();
|
||||
|
||||
void _ServerAdded(ExtendedServerInfo* serverInfo);
|
||||
void _ServerUpdated(ExtendedServerInfo* serverInfo);
|
||||
void _AddingServerFailed(
|
||||
ExtendedServerInfo* serverInfo);
|
||||
void _UpdatingServerFailed(
|
||||
ExtendedServerInfo* serverInfo);
|
||||
void _RemoveServer(ExtendedServerInfo* serverInfo);
|
||||
|
||||
private:
|
||||
Locker fLock;
|
||||
ServerInfoMap* fServerInfos;
|
||||
thread_id fBroadcastListener;
|
||||
vint32 fBroadcastListenerSocket;
|
||||
Listener* fListener;
|
||||
volatile bool fTerminating;
|
||||
};
|
||||
|
||||
// Listener
|
||||
class ServerManager::Listener {
|
||||
public:
|
||||
Listener() {}
|
||||
virtual ~Listener();
|
||||
|
||||
virtual void ServerAdded(ExtendedServerInfo* serverInfo) = 0;
|
||||
virtual void ServerUpdated(ExtendedServerInfo* oldInfo,
|
||||
ExtendedServerInfo* newInfo) = 0;
|
||||
virtual void ServerRemoved(
|
||||
ExtendedServerInfo* serverInfo) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // NET_FS_SERVER_MANAGER_H
|
@ -0,0 +1,127 @@
|
||||
// ServerQueryIterator.cpp
|
||||
|
||||
#include "ServerQueryIterator.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
// constructor
|
||||
ServerQueryIterator::ServerQueryIterator(Volume* volume)
|
||||
: QueryIterator(volume),
|
||||
fRemoteCookie(-1),
|
||||
fShareVolumeIDs(NULL),
|
||||
fShareVolumeCount(0),
|
||||
fShareVolumeIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ServerQueryIterator::~ServerQueryIterator()
|
||||
{
|
||||
}
|
||||
|
||||
// SetRemoteCookie
|
||||
void
|
||||
ServerQueryIterator::SetRemoteCookie(int32 cookie)
|
||||
{
|
||||
fRemoteCookie = cookie;
|
||||
}
|
||||
|
||||
// GetRemoteCookie
|
||||
int32
|
||||
ServerQueryIterator::GetRemoteCookie() const
|
||||
{
|
||||
return fRemoteCookie;
|
||||
}
|
||||
|
||||
// SetEntry
|
||||
status_t
|
||||
ServerQueryIterator::SetEntry(const int32* shareVolumeIDs,
|
||||
int32 shareVolumeCount, const NodeInfo& dirInfo,
|
||||
const EntryInfo& entryInfo)
|
||||
{
|
||||
UnsetEntry();
|
||||
|
||||
if (!shareVolumeIDs || shareVolumeCount <= 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// copy volume IDs
|
||||
if (shareVolumeCount <= IN_OBJECT_ID_COUNT)
|
||||
fShareVolumeIDs = fInObjectIDs;
|
||||
else
|
||||
fShareVolumeIDs = new(std::nothrow) int32[shareVolumeCount];
|
||||
if (!fShareVolumeIDs)
|
||||
return B_NO_MEMORY;
|
||||
fShareVolumeCount = shareVolumeCount;
|
||||
memcpy(fShareVolumeIDs, shareVolumeIDs, shareVolumeCount * 4);
|
||||
|
||||
// copy entry name
|
||||
if (!fEntryName.SetTo(entryInfo.name.GetString())) {
|
||||
UnsetEntry();
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
fDirectoryInfo = dirInfo;
|
||||
fEntryInfo = entryInfo;
|
||||
fEntryInfo.name.SetTo(fEntryName.GetString());
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// UnsetEntry
|
||||
void
|
||||
ServerQueryIterator::UnsetEntry()
|
||||
{
|
||||
if (fShareVolumeIDs && fShareVolumeIDs != fInObjectIDs)
|
||||
delete[] fShareVolumeIDs;
|
||||
fShareVolumeIDs = NULL;
|
||||
|
||||
fShareVolumeCount = 0;
|
||||
fShareVolumeIndex = 0;
|
||||
fEntryName.Unset();
|
||||
fEntryInfo.name.SetTo(NULL);
|
||||
}
|
||||
|
||||
// GetShareVolumeIDs
|
||||
const int32*
|
||||
ServerQueryIterator::GetShareVolumeIDs() const
|
||||
{
|
||||
return fShareVolumeIDs;
|
||||
}
|
||||
|
||||
// CountShareVolumes
|
||||
int32
|
||||
ServerQueryIterator::CountShareVolumes() const
|
||||
{
|
||||
return fShareVolumeCount;
|
||||
}
|
||||
|
||||
// GetDirectoryInfo
|
||||
const NodeInfo&
|
||||
ServerQueryIterator::GetDirectoryInfo() const
|
||||
{
|
||||
return fDirectoryInfo;
|
||||
}
|
||||
|
||||
// GetEntryInfo
|
||||
const EntryInfo&
|
||||
ServerQueryIterator::GetEntryInfo() const
|
||||
{
|
||||
return fEntryInfo;
|
||||
}
|
||||
|
||||
// HasNextShareVolumeID
|
||||
bool
|
||||
ServerQueryIterator::HasNextShareVolumeID() const
|
||||
{
|
||||
return (fShareVolumeIDs && fShareVolumeIndex < fShareVolumeCount);
|
||||
}
|
||||
|
||||
// NextShareVolumeID
|
||||
int32
|
||||
ServerQueryIterator::NextShareVolumeID()
|
||||
{
|
||||
if (!fShareVolumeIDs || fShareVolumeIndex >= fShareVolumeCount)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
return fShareVolumeIDs[fShareVolumeIndex++];
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
// ServerQueryIterator.h
|
||||
|
||||
#ifndef NET_FS_SERVER_QUERY_ITERATOR_H
|
||||
#define NET_FS_SERVER_QUERY_ITERATOR_H
|
||||
|
||||
#include "EntryInfo.h"
|
||||
#include "NodeInfo.h"
|
||||
#include "QueryIterator.h"
|
||||
#include "HashString.h"
|
||||
|
||||
class ServerQueryIterator : public QueryIterator {
|
||||
public:
|
||||
ServerQueryIterator(Volume* volume);
|
||||
virtual ~ServerQueryIterator();
|
||||
|
||||
void SetRemoteCookie(int32 cookie);
|
||||
int32 GetRemoteCookie() const;
|
||||
|
||||
status_t SetEntry(const int32* shareVolumeIDs,
|
||||
int32 shareVolumeCount,
|
||||
const NodeInfo& dirInfo,
|
||||
const EntryInfo& entryInfo);
|
||||
void UnsetEntry();
|
||||
|
||||
const int32* GetShareVolumeIDs() const;
|
||||
int32 CountShareVolumes() const;
|
||||
const NodeInfo& GetDirectoryInfo() const;
|
||||
const EntryInfo& GetEntryInfo() const;
|
||||
|
||||
bool HasNextShareVolumeID() const;
|
||||
int32 NextShareVolumeID();
|
||||
|
||||
private:
|
||||
enum { IN_OBJECT_ID_COUNT = 4 };
|
||||
|
||||
int32 fRemoteCookie;
|
||||
int32* fShareVolumeIDs;
|
||||
int32 fShareVolumeCount;
|
||||
int32 fShareVolumeIndex;
|
||||
NodeInfo fDirectoryInfo;
|
||||
EntryInfo fEntryInfo;
|
||||
HashString fEntryName;
|
||||
int32 fInObjectIDs[IN_OBJECT_ID_COUNT];
|
||||
};
|
||||
|
||||
#endif // NET_FS_SERVER_QUERY_ITERATOR_H
|
415
src/add-ons/kernel/file_systems/netfs/client/ServerVolume.cpp
Normal file
415
src/add-ons/kernel/file_systems/netfs/client/ServerVolume.cpp
Normal file
@ -0,0 +1,415 @@
|
||||
// ServerVolume.cpp
|
||||
|
||||
#include "ServerVolume.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "Compatibility.h"
|
||||
#include "DebugSupport.h"
|
||||
#include "ExtendedServerInfo.h"
|
||||
#include "QueryManager.h"
|
||||
#include "SendReceiveRequest.h"
|
||||
#include "ServerConnection.h"
|
||||
#include "ServerConnectionProvider.h"
|
||||
#include "ServerQueryIterator.h"
|
||||
#include "ShareVolume.h"
|
||||
#include "VolumeEvent.h"
|
||||
#include "VolumeManager.h"
|
||||
#include "VolumeSupport.h"
|
||||
|
||||
// constructor
|
||||
ServerVolume::ServerVolume(VolumeManager* volumeManager,
|
||||
ExtendedServerInfo* serverInfo)
|
||||
: VirtualVolume(volumeManager),
|
||||
fServerInfo(serverInfo),
|
||||
fConnectionProvider(NULL)
|
||||
{
|
||||
fServerInfo->AddReference();
|
||||
}
|
||||
|
||||
// destructor
|
||||
ServerVolume::~ServerVolume()
|
||||
{
|
||||
if (fConnectionProvider)
|
||||
fConnectionProvider->RemoveReference();
|
||||
if (fServerInfo)
|
||||
fServerInfo->RemoveReference();
|
||||
}
|
||||
|
||||
// GetServerAddress
|
||||
NetAddress
|
||||
ServerVolume::GetServerAddress()
|
||||
{
|
||||
AutoLocker<Locker> _(fLock);
|
||||
return fServerInfo->GetAddress();
|
||||
}
|
||||
|
||||
// SetServerInfo
|
||||
void
|
||||
ServerVolume::SetServerInfo(ExtendedServerInfo* serverInfo)
|
||||
{
|
||||
if (!serverInfo)
|
||||
return;
|
||||
|
||||
// set the new info
|
||||
fLock.Lock();
|
||||
fServerInfo->RemoveReference();
|
||||
fServerInfo = serverInfo;
|
||||
fServerInfo->AddReference();
|
||||
Reference<ExtendedServerInfo> newReference(fServerInfo);
|
||||
|
||||
// remove shares, that are no longer there
|
||||
|
||||
// init a directory iterator
|
||||
VirtualDirIterator iterator;
|
||||
iterator.SetDirectory(fRootNode, true);
|
||||
|
||||
// iterate through the directory
|
||||
const char* name;
|
||||
Node* node;
|
||||
while (iterator.GetCurrentEntry(&name, &node)) {
|
||||
iterator.NextEntry();
|
||||
// TODO: Searching by name is currently O(n).
|
||||
bool remove = (!serverInfo->GetShareInfo(name));
|
||||
fLock.Unlock();
|
||||
|
||||
if (remove) {
|
||||
PRINT((" removing share: %s\n", name));
|
||||
if (Volume* volume = GetChildVolume(name)) {
|
||||
volume->SetUnmounting(true);
|
||||
volume->PutVolume();
|
||||
}
|
||||
}
|
||||
|
||||
fLock.Lock();
|
||||
}
|
||||
|
||||
// uninit the directory iterator
|
||||
iterator.SetDirectory(NULL);
|
||||
fLock.Unlock();
|
||||
|
||||
// add new shares
|
||||
int32 count = serverInfo->CountShares();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
ExtendedShareInfo* shareInfo = serverInfo->ShareInfoAt(i);
|
||||
const char* shareName = shareInfo->GetShareName();
|
||||
|
||||
Volume* volume = GetChildVolume(shareName);
|
||||
if (volume) {
|
||||
volume->PutVolume();
|
||||
} else {
|
||||
PRINT((" adding share: %s\n", shareInfo->GetShareName()));
|
||||
status_t error = _AddShare(shareInfo);
|
||||
if (error != B_OK) {
|
||||
ERROR("ServerVolume::SetServerInfo(): ERROR: Failed to add "
|
||||
"share `%s': %s\n", shareName, strerror(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
ServerVolume::Init(const char* name)
|
||||
{
|
||||
status_t error = VirtualVolume::Init(name);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create the server connection provider
|
||||
fConnectionProvider = new ServerConnectionProvider(fVolumeManager,
|
||||
fServerInfo, GetRootID());
|
||||
if (!fConnectionProvider) {
|
||||
Uninit();
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
error = fConnectionProvider->Init();
|
||||
if (error != B_OK) {
|
||||
Uninit();
|
||||
return error;
|
||||
}
|
||||
|
||||
// add share volumes
|
||||
int32 count = fServerInfo->CountShares();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
ExtendedShareInfo* shareInfo = fServerInfo->ShareInfoAt(i);
|
||||
|
||||
error = _AddShare(shareInfo);
|
||||
if (error != B_OK) {
|
||||
ERROR("ServerVolume::Init(): ERROR: Failed to add share `%s': "
|
||||
"%s\n", shareInfo->GetShareName(), strerror(error));
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Uninit
|
||||
void
|
||||
ServerVolume::Uninit()
|
||||
{
|
||||
if (fConnectionProvider)
|
||||
fConnectionProvider->CloseServerConnection();
|
||||
|
||||
VirtualVolume::Uninit();
|
||||
}
|
||||
|
||||
// PrepareToUnmount
|
||||
void
|
||||
ServerVolume::PrepareToUnmount()
|
||||
{
|
||||
VirtualVolume::PrepareToUnmount();
|
||||
}
|
||||
|
||||
// HandleEvent
|
||||
void
|
||||
ServerVolume::HandleEvent(VolumeEvent* event)
|
||||
{
|
||||
if (event->GetType() == CONNECTION_BROKEN_EVENT) {
|
||||
// tell all share volumes that they have been disconnected
|
||||
|
||||
// init a directory iterator
|
||||
fLock.Lock();
|
||||
VirtualDirIterator iterator;
|
||||
iterator.SetDirectory(fRootNode, true);
|
||||
|
||||
// iterate through the directory
|
||||
const char* name;
|
||||
Node* node;
|
||||
while (iterator.GetCurrentEntry(&name, &node)) {
|
||||
iterator.NextEntry();
|
||||
Volume* volume = fVolumeManager->GetVolume(node->GetID());
|
||||
fLock.Unlock();
|
||||
if (ShareVolume* shareVolume = dynamic_cast<ShareVolume*>(volume))
|
||||
shareVolume->ConnectionClosed();
|
||||
if (volume)
|
||||
volume->PutVolume();
|
||||
fLock.Lock();
|
||||
}
|
||||
|
||||
// uninit the directory iterator
|
||||
iterator.SetDirectory(NULL);
|
||||
|
||||
// mark ourselves unmounting
|
||||
SetUnmounting(true);
|
||||
fLock.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- FS -----
|
||||
|
||||
// Unmount
|
||||
status_t
|
||||
ServerVolume::Unmount()
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- queries -----
|
||||
|
||||
// OpenQuery
|
||||
status_t
|
||||
ServerVolume::OpenQuery(const char* queryString, uint32 flags, port_id port,
|
||||
int32 token, QueryIterator** _iterator)
|
||||
{
|
||||
// TODO: Do nothing when there are no (mounted) shares.
|
||||
// get connection
|
||||
ServerConnection* serverConnection
|
||||
= fConnectionProvider->GetExistingServerConnection();
|
||||
if (!serverConnection)
|
||||
return ERROR_NOT_CONNECTED;
|
||||
RequestConnection* connection = serverConnection->GetRequestConnection();
|
||||
|
||||
// create a query iterator and add it to the query manager
|
||||
ServerQueryIterator* iterator = new(std::nothrow) ServerQueryIterator(this);
|
||||
if (!iterator)
|
||||
return B_NO_MEMORY;
|
||||
QueryManager* queryManager = fVolumeManager->GetQueryManager();
|
||||
status_t error = queryManager->AddIterator(iterator);
|
||||
if (error != B_OK) {
|
||||
delete iterator;
|
||||
return error;
|
||||
}
|
||||
QueryIteratorPutter iteratorPutter(queryManager, iterator);
|
||||
|
||||
// prepare the request
|
||||
OpenQueryRequest request;
|
||||
request.queryString.SetTo(queryString);
|
||||
request.flags = flags;
|
||||
request.port = port;
|
||||
request.token = token;
|
||||
|
||||
// send the request
|
||||
OpenQueryReply* reply;
|
||||
error = SendRequest(connection, &request, &reply);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
ObjectDeleter<Request> replyDeleter(reply);
|
||||
if (reply->error != B_OK)
|
||||
RETURN_ERROR(reply->error);
|
||||
|
||||
// set the result
|
||||
iterator->SetRemoteCookie(reply->cookie);
|
||||
*_iterator = iterator;
|
||||
iteratorPutter.Detach();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// FreeQueryIterator
|
||||
void
|
||||
ServerVolume::FreeQueryIterator(QueryIterator* _iterator)
|
||||
{
|
||||
ServerQueryIterator* iterator
|
||||
= dynamic_cast<ServerQueryIterator*>(_iterator);
|
||||
|
||||
int32 cookie = iterator->GetRemoteCookie();
|
||||
if (cookie >= 0) {
|
||||
// prepare the close request
|
||||
CloseRequest request;
|
||||
request.volumeID = -1;
|
||||
request.cookie = cookie;
|
||||
|
||||
// send the request
|
||||
ServerConnection* serverConnection
|
||||
= fConnectionProvider->GetExistingServerConnection();
|
||||
if (serverConnection && serverConnection->IsConnected()) {
|
||||
CloseReply* reply;
|
||||
status_t error = SendRequest(
|
||||
serverConnection->GetRequestConnection(), &request, &reply);
|
||||
if (error == B_OK)
|
||||
delete reply;
|
||||
}
|
||||
}
|
||||
|
||||
delete iterator;
|
||||
}
|
||||
|
||||
// ReadQuery
|
||||
status_t
|
||||
ServerVolume::ReadQuery(QueryIterator* _iterator, struct dirent* buffer,
|
||||
size_t bufferSize, int32 count, int32* countRead)
|
||||
{
|
||||
// get connection
|
||||
ServerConnection* serverConnection
|
||||
= fConnectionProvider->GetExistingServerConnection();
|
||||
if (!serverConnection)
|
||||
return ERROR_NOT_CONNECTED;
|
||||
RequestConnection* connection = serverConnection->GetRequestConnection();
|
||||
|
||||
ServerQueryIterator* iterator
|
||||
= dynamic_cast<ServerQueryIterator*>(_iterator);
|
||||
|
||||
*countRead = 0;
|
||||
|
||||
for (;;) {
|
||||
// if the iterator hasn't cached any more share volume IDs, we need to
|
||||
// ask the server for the next entry
|
||||
if (!iterator->HasNextShareVolumeID()) {
|
||||
// prepare the request
|
||||
ReadQueryRequest request;
|
||||
request.cookie = iterator->GetRemoteCookie();
|
||||
request.count = 1;
|
||||
|
||||
// send the request
|
||||
ReadQueryReply* reply;
|
||||
status_t error = SendRequest(connection, &request, &reply);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
ObjectDeleter<Request> replyDeleter(reply);
|
||||
if (reply->error != B_OK)
|
||||
RETURN_ERROR(reply->error);
|
||||
|
||||
// check, if anything has been read at all
|
||||
if (reply->count == 0) {
|
||||
*countRead = 0;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// update the iterator
|
||||
error = iterator->SetEntry(reply->clientVolumeIDs.GetElements(),
|
||||
reply->clientVolumeIDs.CountElements(), reply->dirInfo,
|
||||
reply->entryInfo);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
|
||||
// get the next concerned share volume and delegate the rest of the work
|
||||
int32 volumeID = iterator->NextShareVolumeID();
|
||||
ShareVolume* shareVolume = _GetShareVolume(volumeID);
|
||||
if (!shareVolume)
|
||||
continue;
|
||||
VolumePutter volumePutter(shareVolume);
|
||||
|
||||
return shareVolume->GetQueryEntry(iterator->GetEntryInfo(),
|
||||
iterator->GetDirectoryInfo(), buffer, bufferSize, countRead);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- private -----
|
||||
|
||||
// _AddShare
|
||||
status_t
|
||||
ServerVolume::_AddShare(ExtendedShareInfo* shareInfo)
|
||||
{
|
||||
// create the share volume
|
||||
ShareVolume* shareVolume = new(std::nothrow) ShareVolume(fVolumeManager,
|
||||
fConnectionProvider, fServerInfo, shareInfo);
|
||||
if (!shareVolume)
|
||||
return B_NO_MEMORY;
|
||||
status_t error = shareVolume->Init(shareInfo->GetShareName());
|
||||
if (error != B_OK) {
|
||||
delete shareVolume;
|
||||
return error;
|
||||
}
|
||||
|
||||
// add the volume to the volume manager
|
||||
error = fVolumeManager->AddVolume(shareVolume);
|
||||
if (error != B_OK) {
|
||||
delete shareVolume;
|
||||
return error;
|
||||
}
|
||||
VolumePutter volumePutter(shareVolume);
|
||||
|
||||
// add the volume to us
|
||||
error = AddChildVolume(shareVolume);
|
||||
if (error != B_OK) {
|
||||
shareVolume->SetUnmounting(true);
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// _GetShareVolume
|
||||
ShareVolume*
|
||||
ServerVolume::_GetShareVolume(int32 volumeID)
|
||||
{
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
VirtualDirIterator dirIterator;
|
||||
dirIterator.SetDirectory(fRootNode, true);
|
||||
|
||||
// iterate through the directory
|
||||
const char* name;
|
||||
Node* node;
|
||||
while (dirIterator.GetCurrentEntry(&name, &node)) {
|
||||
Volume* volume = fVolumeManager->GetVolume(node->GetID());
|
||||
ShareVolume* shareVolume = dynamic_cast<ShareVolume*>(volume);
|
||||
if (shareVolume && shareVolume->GetID() == volumeID)
|
||||
return shareVolume;
|
||||
|
||||
volume->PutVolume();
|
||||
dirIterator.NextEntry();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
55
src/add-ons/kernel/file_systems/netfs/client/ServerVolume.h
Normal file
55
src/add-ons/kernel/file_systems/netfs/client/ServerVolume.h
Normal file
@ -0,0 +1,55 @@
|
||||
// ServerVolume.h
|
||||
|
||||
#ifndef NET_FS_SERVER_VOLUME_H
|
||||
#define NET_FS_SERVER_VOLUME_H
|
||||
|
||||
#include "Locker.h"
|
||||
#include "NetAddress.h"
|
||||
#include "ServerManager.h"
|
||||
#include "VirtualVolume.h"
|
||||
|
||||
class ExtendedServerInfo;
|
||||
class ExtendedShareInfo;
|
||||
class ServerConnectionProvider;
|
||||
class ShareVolume;
|
||||
class VirtualNode;
|
||||
|
||||
class ServerVolume : public VirtualVolume {
|
||||
public:
|
||||
ServerVolume(VolumeManager* volumeManager,
|
||||
ExtendedServerInfo* serverInfo);
|
||||
~ServerVolume();
|
||||
|
||||
NetAddress GetServerAddress();
|
||||
|
||||
void SetServerInfo(ExtendedServerInfo* serverInfo);
|
||||
|
||||
status_t Init(const char* name);
|
||||
void Uninit();
|
||||
|
||||
virtual void PrepareToUnmount();
|
||||
|
||||
virtual void HandleEvent(VolumeEvent* event);
|
||||
|
||||
// FS
|
||||
virtual status_t Unmount();
|
||||
|
||||
// queries
|
||||
virtual status_t OpenQuery(const char* queryString,
|
||||
uint32 flags, port_id port, int32 token,
|
||||
QueryIterator** iterator);
|
||||
virtual void FreeQueryIterator(QueryIterator* iterator);
|
||||
virtual status_t ReadQuery(QueryIterator* iterator,
|
||||
struct dirent* buffer, size_t bufferSize,
|
||||
int32 count, int32* countRead);
|
||||
|
||||
private:
|
||||
status_t _AddShare(ExtendedShareInfo* shareInfo);
|
||||
ShareVolume* _GetShareVolume(int32 volumeID);
|
||||
|
||||
protected:
|
||||
ExtendedServerInfo* fServerInfo;
|
||||
ServerConnectionProvider* fConnectionProvider;
|
||||
};
|
||||
|
||||
#endif // NET_FS_SERVER_VOLUME_H
|
468
src/add-ons/kernel/file_systems/netfs/client/ShareAttrDir.cpp
Normal file
468
src/add-ons/kernel/file_systems/netfs/client/ShareAttrDir.cpp
Normal file
@ -0,0 +1,468 @@
|
||||
// ShareAttrDir.cpp
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Node.h>
|
||||
|
||||
#include "AttrDirInfo.h"
|
||||
#include "AutoDeleter.h"
|
||||
#include "ShareAttrDir.h"
|
||||
|
||||
// compare_attributes
|
||||
//
|
||||
// NULL is considered the maximum
|
||||
static
|
||||
int
|
||||
compare_attributes(const Attribute* a, const Attribute* b)
|
||||
{
|
||||
if (a == b)
|
||||
return 0;
|
||||
if (!a)
|
||||
return 1;
|
||||
if (!b)
|
||||
return -1;
|
||||
|
||||
return strcmp(a->GetName(), b->GetName());
|
||||
}
|
||||
|
||||
// compare_attributes
|
||||
static
|
||||
int
|
||||
compare_attributes(const void* _a, const void* _b)
|
||||
{
|
||||
return compare_attributes(*(const Attribute**)_a, *(const Attribute**)_b);
|
||||
}
|
||||
|
||||
// compare_iterators
|
||||
static
|
||||
int
|
||||
compare_iterators(const ShareAttrDirIterator* a, const ShareAttrDirIterator* b)
|
||||
{
|
||||
return compare_attributes(a->GetCurrentAttribute(),
|
||||
b->GetCurrentAttribute());
|
||||
}
|
||||
|
||||
// compare_iterators
|
||||
static
|
||||
int
|
||||
compare_iterators(const void* _a, const void* _b)
|
||||
{
|
||||
return compare_iterators(*(const ShareAttrDirIterator**)_a,
|
||||
*(const ShareAttrDirIterator**)_b);
|
||||
}
|
||||
|
||||
// constructor
|
||||
Attribute::Attribute(const char* name, const attr_info& info,
|
||||
const void* data)
|
||||
: fInfo(info)
|
||||
{
|
||||
char* nameBuffer = fDataAndName;
|
||||
|
||||
// copy data, if any
|
||||
if (data) {
|
||||
nameBuffer += info.size;
|
||||
memcpy(fDataAndName, data, info.size);
|
||||
|
||||
// store a negative size to indicate we also have the data
|
||||
fInfo.size = -info.size;
|
||||
}
|
||||
|
||||
// copy the name
|
||||
strcpy(nameBuffer, name);
|
||||
}
|
||||
|
||||
// destructor
|
||||
Attribute::~Attribute()
|
||||
{
|
||||
}
|
||||
|
||||
// CreateAttribute
|
||||
status_t
|
||||
Attribute::CreateAttribute(const char* name, const attr_info& info,
|
||||
const void* data, Attribute** attribute)
|
||||
{
|
||||
if (!name || !attribute)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// compute the size
|
||||
int32 nameLen = strlen(name);
|
||||
int32 size = sizeof(Attribute) + nameLen;
|
||||
if (data)
|
||||
size += info.size;
|
||||
|
||||
void* buffer = malloc(size);
|
||||
if (!buffer)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
*attribute = new(buffer) Attribute(name, info, data);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// DeleteAttribute
|
||||
void
|
||||
Attribute::DeleteAttribute(Attribute* attribute)
|
||||
{
|
||||
if (attribute) {
|
||||
attribute->~Attribute();
|
||||
free(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
// GetName
|
||||
const char*
|
||||
Attribute::GetName() const
|
||||
{
|
||||
return (fInfo.size >= 0 ? fDataAndName : fDataAndName - fInfo.size);
|
||||
}
|
||||
|
||||
// GetInfo
|
||||
void
|
||||
Attribute::GetInfo(attr_info* info) const
|
||||
{
|
||||
if (info) {
|
||||
info->type = fInfo.type;
|
||||
info->size = GetSize();
|
||||
}
|
||||
}
|
||||
|
||||
// GetType
|
||||
uint32
|
||||
Attribute::GetType() const
|
||||
{
|
||||
return fInfo.type;
|
||||
}
|
||||
|
||||
// GetSize
|
||||
off_t
|
||||
Attribute::GetSize() const
|
||||
{
|
||||
return (fInfo.size >= 0 ? fInfo.size : -fInfo.size);
|
||||
}
|
||||
|
||||
// GetData
|
||||
const void*
|
||||
Attribute::GetData() const
|
||||
{
|
||||
return (fInfo.size >= 0 ? NULL : fDataAndName);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
ShareAttrDir::ShareAttrDir()
|
||||
: fAttributes(),
|
||||
fRevision(-1),
|
||||
fUpToDate(false)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ShareAttrDir::~ShareAttrDir()
|
||||
{
|
||||
ClearAttrDir();
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
ShareAttrDir::Init(const AttrDirInfo& dirInfo)
|
||||
{
|
||||
if (!dirInfo.isValid)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// get the attributes
|
||||
Attribute** attributes = NULL;
|
||||
int32 count = 0;
|
||||
status_t error = _GetAttributes(dirInfo, attributes, count);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
ArrayDeleter<Attribute*> _(attributes);
|
||||
|
||||
// add the attributes
|
||||
for (int32 i = 0; i < count; i++)
|
||||
fAttributes.Insert(attributes[i]);
|
||||
|
||||
fRevision = dirInfo.revision;
|
||||
fUpToDate = true;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Update
|
||||
status_t
|
||||
ShareAttrDir::Update(const AttrDirInfo& dirInfo,
|
||||
DoublyLinkedList<ShareAttrDirIterator>* iterators)
|
||||
{
|
||||
if (!dirInfo.isValid)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (fRevision >= dirInfo.revision)
|
||||
return B_OK;
|
||||
|
||||
// allocate an array for the old attributes
|
||||
int32 oldCount = fAttributes.Size();
|
||||
Attribute** oldAttributes = new(std::nothrow) Attribute*[oldCount];
|
||||
if (!oldAttributes)
|
||||
return B_NO_MEMORY;
|
||||
ArrayDeleter<Attribute*> _(oldAttributes);
|
||||
|
||||
// get the new attributes
|
||||
Attribute** newAttributes = NULL;
|
||||
int32 newCount = 0;
|
||||
status_t error = _GetAttributes(dirInfo, newAttributes, newCount);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
ArrayDeleter<Attribute*> _2(newAttributes);
|
||||
|
||||
// sort the iterators
|
||||
int32 iteratorCount = (iterators ? iterators->Count() : 0);
|
||||
if (iteratorCount > 0) {
|
||||
// allocate an array
|
||||
ShareAttrDirIterator** _iterators
|
||||
= new(std::nothrow) ShareAttrDirIterator*[iteratorCount];
|
||||
if (!_iterators)
|
||||
return B_NO_MEMORY;
|
||||
ArrayDeleter<ShareAttrDirIterator*> _3(_iterators);
|
||||
|
||||
// move the iterators
|
||||
for (int32 i = 0; i < iteratorCount; i++) {
|
||||
ShareAttrDirIterator* iterator = iterators->First();
|
||||
_iterators[i] = iterator;
|
||||
iterators->Remove(iterator);
|
||||
}
|
||||
|
||||
// sort them
|
||||
qsort(_iterators, iteratorCount, sizeof(ShareAttrDirIterator*),
|
||||
compare_iterators);
|
||||
|
||||
// move them back into the list
|
||||
for (int32 i = 0; i < iteratorCount; i++)
|
||||
iterators->Insert(_iterators[i]);
|
||||
}
|
||||
|
||||
// remove the old attributes
|
||||
for (int32 i = 0; i < oldCount; i++) {
|
||||
Attribute* attribute = fAttributes.GetFirst();
|
||||
oldAttributes[i] = attribute;
|
||||
fAttributes.Remove(attribute);
|
||||
}
|
||||
|
||||
// add the new attributes
|
||||
int32 oldIndex = 0;
|
||||
int32 newIndex = 0;
|
||||
ShareAttrDirIterator* iterator = (iterators ? iterators->First() : NULL);
|
||||
while (oldIndex < oldCount || newIndex < newCount) {
|
||||
Attribute* oldAttr = (oldCount > 0 ? oldAttributes[oldIndex] : NULL);
|
||||
Attribute* newAttr = (newCount > 0 ? newAttributes[newIndex] : NULL);
|
||||
int cmp = compare_attributes(oldAttr, newAttr);
|
||||
if (cmp < 0) {
|
||||
// oldAttr is obsolete: move all iterators pointing to it to the
|
||||
// next new attribute
|
||||
while (iterator && iterator->GetCurrentAttribute() == oldAttr) {
|
||||
iterator->SetCurrentAttribute(newAttr);
|
||||
iterator = iterators->GetNext(iterator);
|
||||
}
|
||||
oldIndex++;
|
||||
} else if (cmp > 0) {
|
||||
// newAttr is new
|
||||
fAttributes.Insert(newAttr);
|
||||
newIndex++;
|
||||
} else {
|
||||
// oldAttr == newAttr
|
||||
fAttributes.Insert(newAttr);
|
||||
oldIndex++;
|
||||
newIndex++;
|
||||
|
||||
// move the attributes pointing to this attribute
|
||||
while (iterator && iterator->GetCurrentAttribute() == oldAttr) {
|
||||
iterator->SetCurrentAttribute(newAttr);
|
||||
iterator = iterators->GetNext(iterator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete the old attributes
|
||||
for (int32 i = 0; i < oldCount; i++)
|
||||
Attribute::DeleteAttribute(oldAttributes[i]);
|
||||
|
||||
fRevision = dirInfo.revision;
|
||||
fUpToDate = true;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// SetRevision
|
||||
void
|
||||
ShareAttrDir::SetRevision(int64 revision)
|
||||
{
|
||||
fRevision = revision;
|
||||
}
|
||||
|
||||
// GetRevision
|
||||
int64
|
||||
ShareAttrDir::GetRevision() const
|
||||
{
|
||||
return fRevision;
|
||||
}
|
||||
|
||||
// SetUpToDate
|
||||
void
|
||||
ShareAttrDir::SetUpToDate(bool upToDate)
|
||||
{
|
||||
fUpToDate = upToDate;
|
||||
}
|
||||
|
||||
// IsUpToDate
|
||||
bool
|
||||
ShareAttrDir::IsUpToDate() const
|
||||
{
|
||||
return fUpToDate;
|
||||
}
|
||||
|
||||
// ClearAttrDir
|
||||
void
|
||||
ShareAttrDir::ClearAttrDir()
|
||||
{
|
||||
while (Attribute* attribute = GetFirstAttribute())
|
||||
RemoveAttribute(attribute);
|
||||
}
|
||||
|
||||
// AddAttribute
|
||||
status_t
|
||||
ShareAttrDir::AddAttribute(const char* name, const attr_info& info,
|
||||
const void* data)
|
||||
{
|
||||
if (!name || GetAttribute(name))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// create the attribute
|
||||
Attribute* attribute;
|
||||
status_t error = Attribute::CreateAttribute(name, info, data, &attribute);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// add the attribute
|
||||
fAttributes.Insert(attribute);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// RemoveAttribute
|
||||
bool
|
||||
ShareAttrDir::RemoveAttribute(const char* name)
|
||||
{
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
for (SLList<Attribute>::Iterator it = fAttributes.GetIterator();
|
||||
it.HasNext();) {
|
||||
Attribute* attribute = it.Next();
|
||||
if (strcmp(attribute->GetName(), name) == 0) {
|
||||
it.Remove();
|
||||
Attribute::DeleteAttribute(attribute);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveAttribute
|
||||
void
|
||||
ShareAttrDir::RemoveAttribute(Attribute* attribute)
|
||||
{
|
||||
if (!attribute)
|
||||
return;
|
||||
|
||||
fAttributes.Remove(attribute);
|
||||
Attribute::DeleteAttribute(attribute);
|
||||
}
|
||||
|
||||
// GetAttribute
|
||||
Attribute*
|
||||
ShareAttrDir::GetAttribute(const char* name) const
|
||||
{
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
for (SLList<Attribute>::ConstIterator it = fAttributes.GetIterator();
|
||||
it.HasNext();) {
|
||||
Attribute* attribute = it.Next();
|
||||
if (strcmp(attribute->GetName(), name) == 0)
|
||||
return attribute;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// GetFirstAttribute
|
||||
Attribute*
|
||||
ShareAttrDir::GetFirstAttribute() const
|
||||
{
|
||||
return fAttributes.GetFirst();
|
||||
}
|
||||
|
||||
// GetNextAttribute
|
||||
Attribute*
|
||||
ShareAttrDir::GetNextAttribute(Attribute* attribute) const
|
||||
{
|
||||
return (attribute ? fAttributes.GetNext(attribute) : NULL);
|
||||
}
|
||||
|
||||
// _GetAttributes
|
||||
status_t
|
||||
ShareAttrDir::_GetAttributes(const AttrDirInfo& dirInfo,
|
||||
Attribute**& _attributes, int32& _count)
|
||||
{
|
||||
if (!dirInfo.isValid)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
int32 count = dirInfo.attributeInfos.CountElements();
|
||||
const AttributeInfo* attrInfos = dirInfo.attributeInfos.GetElements();
|
||||
|
||||
// allocate an attribute array
|
||||
Attribute** attributes = NULL;
|
||||
if (count > 0) {
|
||||
attributes = new(std::nothrow) Attribute*[count];
|
||||
if (!attributes)
|
||||
return B_NO_MEMORY;
|
||||
memset(attributes, 0, sizeof(Attribute*) * count);
|
||||
}
|
||||
|
||||
status_t error = B_OK;
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
const AttributeInfo& attrInfo = attrInfos[i];
|
||||
|
||||
// create the attribute
|
||||
const void* data = attrInfo.data.GetData();
|
||||
if (data && attrInfo.data.GetSize() != attrInfo.info.size)
|
||||
data = NULL;
|
||||
error = Attribute::CreateAttribute(attrInfo.name.GetString(),
|
||||
attrInfo.info, data, attributes + i);
|
||||
if (error != B_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
// cleanup on error
|
||||
if (error != B_OK) {
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
if (Attribute* attribute = attributes[i])
|
||||
Attribute::DeleteAttribute(attribute);
|
||||
}
|
||||
delete[] attributes;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// sort the attribute array
|
||||
if (count > 0)
|
||||
qsort(attributes, count, sizeof(Attribute*), compare_attributes);
|
||||
|
||||
_attributes = attributes;
|
||||
_count = count;
|
||||
return B_OK;
|
||||
}
|
||||
|
79
src/add-ons/kernel/file_systems/netfs/client/ShareAttrDir.h
Normal file
79
src/add-ons/kernel/file_systems/netfs/client/ShareAttrDir.h
Normal file
@ -0,0 +1,79 @@
|
||||
// ShareAttrDir.h
|
||||
|
||||
#ifndef NET_FS_SHARE_ATTR_DIR_H
|
||||
#define NET_FS_SHARE_ATTR_DIR_H
|
||||
|
||||
#include <fs_attr.h>
|
||||
|
||||
#include "ShareAttrDirIterator.h"
|
||||
#include "SLList.h"
|
||||
|
||||
class AttrDirInfo;
|
||||
class AttributeInfo;
|
||||
class BNode;
|
||||
|
||||
// Attribute
|
||||
class Attribute : public SLListLinkImpl<Attribute> {
|
||||
Attribute(const char* name,
|
||||
const attr_info& info, const void* data);
|
||||
~Attribute();
|
||||
public:
|
||||
static status_t CreateAttribute(const char* name,
|
||||
const attr_info& info, const void* data,
|
||||
Attribute** attribute);
|
||||
static void DeleteAttribute(Attribute* attribute);
|
||||
|
||||
const char* GetName() const;
|
||||
void GetInfo(attr_info* info) const;
|
||||
uint32 GetType() const;
|
||||
off_t GetSize() const;
|
||||
const void* GetData() const;
|
||||
|
||||
private:
|
||||
attr_info fInfo;
|
||||
char fDataAndName[1];
|
||||
};
|
||||
|
||||
// ShareAttrDir
|
||||
class ShareAttrDir {
|
||||
public:
|
||||
ShareAttrDir();
|
||||
~ShareAttrDir();
|
||||
|
||||
status_t Init(const AttrDirInfo& dirInfo);
|
||||
status_t Update(const AttrDirInfo& dirInfo,
|
||||
DoublyLinkedList<ShareAttrDirIterator>*
|
||||
iterators);
|
||||
|
||||
void SetRevision(int64 revision);
|
||||
int64 GetRevision() const;
|
||||
|
||||
void SetUpToDate(bool upToDate);
|
||||
bool IsUpToDate() const;
|
||||
|
||||
// These modifying methods are currently used internally only.
|
||||
// Init()/Update() should be sufficient.
|
||||
void ClearAttrDir();
|
||||
|
||||
status_t AddAttribute(const char* name,
|
||||
const attr_info& info, const void* data);
|
||||
bool RemoveAttribute(const char* name);
|
||||
void RemoveAttribute(Attribute* attribute);
|
||||
|
||||
Attribute* GetAttribute(const char* name) const;
|
||||
Attribute* GetFirstAttribute() const;
|
||||
Attribute* GetNextAttribute(Attribute* attribute) const;
|
||||
|
||||
private:
|
||||
status_t _GetAttributes(const AttrDirInfo& dirInfo,
|
||||
Attribute**& attributes, int32& count);
|
||||
|
||||
private:
|
||||
SLList<Attribute> fAttributes;
|
||||
// TODO: Rethink whether we rather want an array.
|
||||
int64 fRevision;
|
||||
bool fUpToDate; // to enforce reloading even if
|
||||
// a revision is cached
|
||||
};
|
||||
|
||||
#endif // NET_FS_SHARE_ATTR_DIR_H
|
@ -0,0 +1,57 @@
|
||||
// ShareAttrDirIterator.cpp
|
||||
|
||||
#include "ShareAttrDirIterator.h"
|
||||
|
||||
#include "ShareAttrDir.h"
|
||||
|
||||
// constructor
|
||||
ShareAttrDirIterator::ShareAttrDirIterator()
|
||||
:
|
||||
fAttrDir(NULL),
|
||||
fCurrentAttribute(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ShareAttrDirIterator::~ShareAttrDirIterator()
|
||||
{
|
||||
}
|
||||
|
||||
// SetAttrDir
|
||||
void
|
||||
ShareAttrDirIterator::SetAttrDir(ShareAttrDir* attrDir)
|
||||
{
|
||||
fAttrDir = attrDir;
|
||||
fCurrentAttribute = (fAttrDir ? fAttrDir->GetFirstAttribute() : NULL);
|
||||
}
|
||||
|
||||
// SetCurrentAttribute
|
||||
void
|
||||
ShareAttrDirIterator::SetCurrentAttribute(Attribute* attribute)
|
||||
{
|
||||
fCurrentAttribute = attribute;
|
||||
}
|
||||
|
||||
// GetCurrentAttribute
|
||||
Attribute*
|
||||
ShareAttrDirIterator::GetCurrentAttribute() const
|
||||
{
|
||||
return fCurrentAttribute;
|
||||
}
|
||||
|
||||
// NextAttribute
|
||||
Attribute*
|
||||
ShareAttrDirIterator::NextAttribute()
|
||||
{
|
||||
if (fAttrDir && fCurrentAttribute)
|
||||
fCurrentAttribute = fAttrDir->GetNextAttribute(fCurrentAttribute);
|
||||
return fCurrentAttribute;
|
||||
}
|
||||
|
||||
// Rewind
|
||||
void
|
||||
ShareAttrDirIterator::Rewind()
|
||||
{
|
||||
fCurrentAttribute = (fAttrDir ? fAttrDir->GetFirstAttribute() : NULL);
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
// ShareAttrDirIterator.h
|
||||
|
||||
#ifndef NET_FS_SHARE_ATTR_DIR_ITERATOR_H
|
||||
#define NET_FS_SHARE_ATTR_DIR_ITERATOR_H
|
||||
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
class Attribute;
|
||||
class ShareAttrDir;
|
||||
|
||||
class ShareAttrDirIterator
|
||||
: public DoublyLinkedListLinkImpl<ShareAttrDirIterator> {
|
||||
public:
|
||||
ShareAttrDirIterator();
|
||||
~ShareAttrDirIterator();
|
||||
|
||||
void SetAttrDir(ShareAttrDir* attrDir);
|
||||
|
||||
void SetCurrentAttribute(Attribute* attribute);
|
||||
Attribute* GetCurrentAttribute() const;
|
||||
Attribute* NextAttribute();
|
||||
void Rewind();
|
||||
|
||||
private:
|
||||
ShareAttrDir* fAttrDir;
|
||||
Attribute* fCurrentAttribute;
|
||||
};
|
||||
|
||||
#endif // NET_FS_SHARE_ATTR_DIR_ITERATOR_H
|
518
src/add-ons/kernel/file_systems/netfs/client/ShareNode.cpp
Normal file
518
src/add-ons/kernel/file_systems/netfs/client/ShareNode.cpp
Normal file
@ -0,0 +1,518 @@
|
||||
// ShareNode.cpp
|
||||
|
||||
#include "ShareNode.h"
|
||||
|
||||
#include "ShareAttrDir.h"
|
||||
|
||||
// constructor
|
||||
ShareDirEntry::ShareDirEntry(ShareDir* directory, const char* name,
|
||||
ShareNode* node)
|
||||
:
|
||||
BReferenceable(true),
|
||||
fDirectory(directory),
|
||||
fName(name),
|
||||
fNode(node),
|
||||
fRevision(-1)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ShareDirEntry::~ShareDirEntry()
|
||||
{
|
||||
}
|
||||
|
||||
// InitCheck
|
||||
status_t
|
||||
ShareDirEntry::InitCheck() const
|
||||
{
|
||||
if (fName.GetLength() == 0)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// GetDirectory
|
||||
ShareDir*
|
||||
ShareDirEntry::GetDirectory() const
|
||||
{
|
||||
return fDirectory;
|
||||
}
|
||||
|
||||
// GetName
|
||||
const char*
|
||||
ShareDirEntry::GetName() const
|
||||
{
|
||||
return fName.GetString();
|
||||
}
|
||||
|
||||
// GetNode
|
||||
ShareNode*
|
||||
ShareDirEntry::GetNode() const
|
||||
{
|
||||
return fNode;
|
||||
}
|
||||
|
||||
// SetRevision
|
||||
void
|
||||
ShareDirEntry::SetRevision(int64 revision)
|
||||
{
|
||||
fRevision = revision;
|
||||
}
|
||||
|
||||
// GetRevision
|
||||
int64
|
||||
ShareDirEntry::GetRevision() const
|
||||
{
|
||||
return fRevision;
|
||||
}
|
||||
|
||||
// IsActualEntry
|
||||
bool
|
||||
ShareDirEntry::IsActualEntry() const
|
||||
{
|
||||
return (fName.GetLength() > 0 && fName != "." && fName != "..");
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
ShareNode::ShareNode(Volume* volume, vnode_id id, const NodeInfo* nodeInfo)
|
||||
:
|
||||
Node(volume, id),
|
||||
fInfo(),
|
||||
fReferringEntries(),
|
||||
fAttrDir(NULL)
|
||||
{
|
||||
if (nodeInfo) {
|
||||
fInfo = *nodeInfo;
|
||||
} else {
|
||||
// init the stat data at least a bit, if no node info is given
|
||||
fInfo.st.st_dev = -1;
|
||||
fInfo.st.st_ino = -1;
|
||||
fInfo.st.st_mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP
|
||||
| S_IROTH | S_IXOTH;
|
||||
fInfo.st.st_nlink = 1;
|
||||
fInfo.st.st_size = 1;
|
||||
fInfo.st.st_blksize = 1024;
|
||||
fInfo.st.st_crtime = 0;
|
||||
fInfo.st.st_ctime = fInfo.st.st_mtime = fInfo.st.st_atime
|
||||
= fInfo.st.st_crtime;
|
||||
|
||||
// negative revision, to make sure it is updated
|
||||
fInfo.revision = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
ShareNode::~ShareNode()
|
||||
{
|
||||
delete fAttrDir;
|
||||
}
|
||||
|
||||
// GetNodeInfo
|
||||
const NodeInfo&
|
||||
ShareNode::GetNodeInfo() const
|
||||
{
|
||||
return fInfo;
|
||||
}
|
||||
|
||||
// GetRemoteID
|
||||
NodeID
|
||||
ShareNode::GetRemoteID() const
|
||||
{
|
||||
return fInfo.GetID();
|
||||
}
|
||||
|
||||
// Update
|
||||
void
|
||||
ShareNode::Update(const NodeInfo& nodeInfo)
|
||||
{
|
||||
if (fInfo.revision < nodeInfo.revision)
|
||||
fInfo = nodeInfo;
|
||||
}
|
||||
|
||||
// AddReferringEntry
|
||||
void
|
||||
ShareNode::AddReferringEntry(ShareDirEntry* entry)
|
||||
{
|
||||
if (entry)
|
||||
fReferringEntries.Insert(entry);
|
||||
}
|
||||
|
||||
// RemoveReferringEntry
|
||||
void
|
||||
ShareNode::RemoveReferringEntry(ShareDirEntry* entry)
|
||||
{
|
||||
if (entry)
|
||||
fReferringEntries.Remove(entry);
|
||||
}
|
||||
|
||||
// GetFirstReferringEntry
|
||||
ShareDirEntry*
|
||||
ShareNode::GetFirstReferringEntry() const
|
||||
{
|
||||
return fReferringEntries.GetFirst();
|
||||
}
|
||||
|
||||
// GetNextReferringEntry
|
||||
ShareDirEntry*
|
||||
ShareNode::GetNextReferringEntry(ShareDirEntry* entry) const
|
||||
{
|
||||
return (entry ? fReferringEntries.GetNext(entry) : NULL);
|
||||
}
|
||||
|
||||
// GetActualReferringEntry
|
||||
ShareDirEntry*
|
||||
ShareNode::GetActualReferringEntry() const
|
||||
{
|
||||
for (ShareDirEntry* entry = GetFirstReferringEntry();
|
||||
entry;
|
||||
entry = GetNextReferringEntry(entry)) {
|
||||
if (entry->IsActualEntry())
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// SetAttrDir
|
||||
void
|
||||
ShareNode::SetAttrDir(ShareAttrDir* attrDir)
|
||||
{
|
||||
delete fAttrDir;
|
||||
fAttrDir = attrDir;
|
||||
}
|
||||
|
||||
// GetAttrDir
|
||||
ShareAttrDir*
|
||||
ShareNode::GetAttrDir() const
|
||||
{
|
||||
return fAttrDir;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
ShareDirIterator::ShareDirIterator()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ShareDirIterator::~ShareDirIterator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
LocalShareDirIterator::LocalShareDirIterator()
|
||||
: fDirectory(NULL),
|
||||
fCurrentEntry(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
LocalShareDirIterator::~LocalShareDirIterator()
|
||||
{
|
||||
SetDirectory(NULL);
|
||||
}
|
||||
|
||||
// SetDirectory
|
||||
void
|
||||
LocalShareDirIterator::SetDirectory(ShareDir* directory)
|
||||
{
|
||||
// unset the old directory
|
||||
if (fDirectory)
|
||||
fDirectory->RemoveDirIterator(this);
|
||||
|
||||
// set the new directory
|
||||
fDirectory = directory;
|
||||
if (fDirectory) {
|
||||
fDirectory->AddDirIterator(this);
|
||||
fCurrentEntry = fDirectory->GetFirstEntry();
|
||||
}
|
||||
}
|
||||
|
||||
// GetCurrentEntry
|
||||
ShareDirEntry*
|
||||
LocalShareDirIterator::GetCurrentEntry() const
|
||||
{
|
||||
return fCurrentEntry;
|
||||
}
|
||||
|
||||
// NextEntry
|
||||
void
|
||||
LocalShareDirIterator::NextEntry()
|
||||
{
|
||||
if (!fDirectory || !fCurrentEntry)
|
||||
return;
|
||||
|
||||
fCurrentEntry = fDirectory->GetNextEntry(fCurrentEntry);
|
||||
}
|
||||
|
||||
// Rewind
|
||||
void
|
||||
LocalShareDirIterator::Rewind()
|
||||
{
|
||||
fCurrentEntry = (fDirectory ? fDirectory->GetFirstEntry() : NULL);
|
||||
}
|
||||
|
||||
// IsDone
|
||||
bool
|
||||
LocalShareDirIterator::IsDone() const
|
||||
{
|
||||
return !fCurrentEntry;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
RemoteShareDirIterator::RemoteShareDirIterator()
|
||||
: fCookie(-1),
|
||||
fCapacity(kRemoteShareDirIteratorCapacity),
|
||||
fCount(0),
|
||||
fIndex(0),
|
||||
fRevision(-1),
|
||||
fDone(false),
|
||||
fRewind(false)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
RemoteShareDirIterator::~RemoteShareDirIterator()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
// GetCurrentEntry
|
||||
ShareDirEntry*
|
||||
RemoteShareDirIterator::GetCurrentEntry() const
|
||||
{
|
||||
return (!fRewind && fIndex < fCount ? fEntries[fIndex] : NULL);
|
||||
}
|
||||
|
||||
// NextEntry
|
||||
void
|
||||
RemoteShareDirIterator::NextEntry()
|
||||
{
|
||||
if (fIndex < fCount)
|
||||
fIndex++;
|
||||
}
|
||||
|
||||
// Rewind
|
||||
void
|
||||
RemoteShareDirIterator::Rewind()
|
||||
{
|
||||
fRewind = true;
|
||||
fDone = false;
|
||||
}
|
||||
|
||||
// IsDone
|
||||
bool
|
||||
RemoteShareDirIterator::IsDone() const
|
||||
{
|
||||
return fDone;
|
||||
}
|
||||
|
||||
// GetCapacity
|
||||
int32
|
||||
RemoteShareDirIterator::GetCapacity() const
|
||||
{
|
||||
return fCapacity;
|
||||
}
|
||||
|
||||
// SetCookie
|
||||
void
|
||||
RemoteShareDirIterator::SetCookie(int32 cookie)
|
||||
{
|
||||
fCookie = cookie;
|
||||
}
|
||||
|
||||
// GetCookie
|
||||
int32
|
||||
RemoteShareDirIterator::GetCookie() const
|
||||
{
|
||||
return fCookie;
|
||||
}
|
||||
|
||||
// Clear
|
||||
void
|
||||
RemoteShareDirIterator::Clear()
|
||||
{
|
||||
for (int32 i = 0; i < fCount; i++)
|
||||
fEntries[i]->RemoveReference();
|
||||
fCount = 0;
|
||||
fIndex = 0;
|
||||
fDone = false;
|
||||
fRewind = false;
|
||||
}
|
||||
|
||||
// AddEntry
|
||||
bool
|
||||
RemoteShareDirIterator::AddEntry(ShareDirEntry* entry)
|
||||
{
|
||||
if (!entry || fCount >= fCapacity)
|
||||
return false;
|
||||
|
||||
fEntries[fCount++] = entry;
|
||||
entry->AddReference();
|
||||
return true;
|
||||
}
|
||||
|
||||
// SetRevision
|
||||
void
|
||||
RemoteShareDirIterator::SetRevision(int64 revision)
|
||||
{
|
||||
fRevision = revision;
|
||||
}
|
||||
|
||||
// GetRevision
|
||||
int64
|
||||
RemoteShareDirIterator::GetRevision() const
|
||||
{
|
||||
return fRevision;
|
||||
}
|
||||
|
||||
// SetDone
|
||||
void
|
||||
RemoteShareDirIterator::SetDone(bool done)
|
||||
{
|
||||
fDone = done;
|
||||
}
|
||||
|
||||
// GetRewind
|
||||
bool
|
||||
RemoteShareDirIterator::GetRewind() const
|
||||
{
|
||||
return fRewind;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
ShareDir::ShareDir(Volume* volume, vnode_id id, const NodeInfo* nodeInfo)
|
||||
: ShareNode(volume, id, nodeInfo),
|
||||
fEntries(),
|
||||
fIterators(),
|
||||
fEntryCreatedEventRevision(-1),
|
||||
fEntryRemovedEventRevision(-1),
|
||||
fIsComplete(false)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ShareDir::~ShareDir()
|
||||
{
|
||||
}
|
||||
|
||||
// UpdateEntryCreatedEventRevision
|
||||
void
|
||||
ShareDir::UpdateEntryCreatedEventRevision(int64 revision)
|
||||
{
|
||||
if (revision > fEntryCreatedEventRevision)
|
||||
fEntryCreatedEventRevision = revision;
|
||||
}
|
||||
|
||||
// GetEntryCreatedEventRevision
|
||||
int64
|
||||
ShareDir::GetEntryCreatedEventRevision() const
|
||||
{
|
||||
return fEntryCreatedEventRevision;
|
||||
}
|
||||
|
||||
// UpdateEntryRemovedEventRevision
|
||||
void
|
||||
ShareDir::UpdateEntryRemovedEventRevision(int64 revision)
|
||||
{
|
||||
if (revision > fEntryRemovedEventRevision)
|
||||
fEntryRemovedEventRevision = revision;
|
||||
}
|
||||
|
||||
// GetEntryRemovedEventRevision
|
||||
int64
|
||||
ShareDir::GetEntryRemovedEventRevision() const
|
||||
{
|
||||
return fEntryRemovedEventRevision;
|
||||
}
|
||||
|
||||
// SetComplete
|
||||
void
|
||||
ShareDir::SetComplete(bool complete)
|
||||
{
|
||||
fIsComplete = complete;
|
||||
}
|
||||
|
||||
// IsComplete
|
||||
bool
|
||||
ShareDir::IsComplete() const
|
||||
{
|
||||
return fIsComplete;
|
||||
}
|
||||
|
||||
// AddEntry
|
||||
void
|
||||
ShareDir::AddEntry(ShareDirEntry* entry)
|
||||
{
|
||||
if (entry)
|
||||
fEntries.Insert(entry);
|
||||
}
|
||||
|
||||
// RemoveEntry
|
||||
void
|
||||
ShareDir::RemoveEntry(ShareDirEntry* entry)
|
||||
{
|
||||
if (entry) {
|
||||
// update the directory iterators pointing to the removed entry
|
||||
for (LocalShareDirIterator* iterator = fIterators.First();
|
||||
iterator;
|
||||
iterator = fIterators.GetNext(iterator)) {
|
||||
if (iterator->GetCurrentEntry() == entry)
|
||||
iterator->NextEntry();
|
||||
}
|
||||
|
||||
fEntries.Remove(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// GetFirstEntry
|
||||
ShareDirEntry*
|
||||
ShareDir::GetFirstEntry() const
|
||||
{
|
||||
return fEntries.First();
|
||||
}
|
||||
|
||||
// GetNextEntry
|
||||
ShareDirEntry*
|
||||
ShareDir::GetNextEntry(ShareDirEntry* entry) const
|
||||
{
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
return fEntries.GetNext(entry);
|
||||
}
|
||||
|
||||
// AddDirIterator
|
||||
void
|
||||
ShareDir::AddDirIterator(LocalShareDirIterator* iterator)
|
||||
{
|
||||
if (!iterator)
|
||||
return;
|
||||
|
||||
fIterators.Insert(iterator);
|
||||
}
|
||||
|
||||
// RemoveDirIterator
|
||||
void
|
||||
ShareDir::RemoveDirIterator(LocalShareDirIterator* iterator)
|
||||
{
|
||||
if (!iterator)
|
||||
return;
|
||||
|
||||
fIterators.Remove(iterator);
|
||||
}
|
||||
|
193
src/add-ons/kernel/file_systems/netfs/client/ShareNode.h
Normal file
193
src/add-ons/kernel/file_systems/netfs/client/ShareNode.h
Normal file
@ -0,0 +1,193 @@
|
||||
// Node.h
|
||||
|
||||
#ifndef NET_FS_SHARE_NODE_H
|
||||
#define NET_FS_SHARE_NODE_H
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include "HashString.h"
|
||||
#include "Node.h"
|
||||
#include "NodeInfo.h"
|
||||
#include "SLList.h"
|
||||
|
||||
class ShareAttrDir;
|
||||
class ShareDir;
|
||||
class ShareNode;
|
||||
|
||||
static const int32 kRemoteShareDirIteratorCapacity = 32;
|
||||
|
||||
// ShareDirEntry
|
||||
class ShareDirEntry : public BReferenceable,
|
||||
public DoublyLinkedListLinkImpl<ShareDirEntry>,
|
||||
public SLListLinkImpl<ShareDirEntry> {
|
||||
public:
|
||||
ShareDirEntry(ShareDir* directory,
|
||||
const char* name, ShareNode* node);
|
||||
~ShareDirEntry();
|
||||
|
||||
status_t InitCheck() const;
|
||||
|
||||
ShareDir* GetDirectory() const;
|
||||
const char* GetName() const;
|
||||
ShareNode* GetNode() const;
|
||||
|
||||
void SetRevision(int64 revision);
|
||||
int64 GetRevision() const;
|
||||
|
||||
bool IsActualEntry() const;
|
||||
|
||||
private:
|
||||
ShareDir* fDirectory;
|
||||
HashString fName;
|
||||
ShareNode* fNode;
|
||||
int64 fRevision;
|
||||
};
|
||||
|
||||
// ShareNode
|
||||
class ShareNode : public Node {
|
||||
public:
|
||||
ShareNode(Volume* volume, vnode_id id,
|
||||
const NodeInfo* nodeInfo);
|
||||
virtual ~ShareNode();
|
||||
|
||||
const NodeInfo& GetNodeInfo() const;
|
||||
|
||||
NodeID GetRemoteID() const;
|
||||
|
||||
void Update(const NodeInfo& nodeInfo);
|
||||
|
||||
void AddReferringEntry(ShareDirEntry* entry);
|
||||
void RemoveReferringEntry(ShareDirEntry* entry);
|
||||
ShareDirEntry* GetFirstReferringEntry() const;
|
||||
ShareDirEntry* GetNextReferringEntry(
|
||||
ShareDirEntry* entry) const;
|
||||
ShareDirEntry* GetActualReferringEntry() const;
|
||||
|
||||
void SetAttrDir(ShareAttrDir* attrDir);
|
||||
ShareAttrDir* GetAttrDir() const;
|
||||
|
||||
private:
|
||||
NodeInfo fInfo;
|
||||
SLList<ShareDirEntry> fReferringEntries;
|
||||
ShareAttrDir* fAttrDir;
|
||||
};
|
||||
|
||||
// ShareDirIterator
|
||||
class ShareDirIterator {
|
||||
public:
|
||||
ShareDirIterator();
|
||||
virtual ~ShareDirIterator();
|
||||
|
||||
virtual ShareDirEntry* GetCurrentEntry() const = 0;
|
||||
virtual void NextEntry() = 0;
|
||||
virtual void Rewind() = 0;
|
||||
virtual bool IsDone() const = 0;
|
||||
};
|
||||
|
||||
// LocalShareDirIterator
|
||||
class LocalShareDirIterator : public ShareDirIterator,
|
||||
public DoublyLinkedListLinkImpl<LocalShareDirIterator> {
|
||||
public:
|
||||
LocalShareDirIterator();
|
||||
~LocalShareDirIterator();
|
||||
|
||||
void SetDirectory(ShareDir* directory);
|
||||
|
||||
virtual ShareDirEntry* GetCurrentEntry() const;
|
||||
virtual void NextEntry();
|
||||
virtual void Rewind();
|
||||
virtual bool IsDone() const;
|
||||
|
||||
private:
|
||||
ShareDir* fDirectory;
|
||||
ShareDirEntry* fCurrentEntry;
|
||||
};
|
||||
|
||||
// RemoteShareDirIterator
|
||||
class RemoteShareDirIterator : public ShareDirIterator {
|
||||
public:
|
||||
RemoteShareDirIterator();
|
||||
~RemoteShareDirIterator();
|
||||
|
||||
virtual ShareDirEntry* GetCurrentEntry() const;
|
||||
virtual void NextEntry();
|
||||
virtual void Rewind();
|
||||
virtual bool IsDone() const;
|
||||
|
||||
int32 GetCapacity() const;
|
||||
|
||||
void SetCookie(int32 cookie);
|
||||
int32 GetCookie() const;
|
||||
|
||||
void Clear();
|
||||
bool AddEntry(ShareDirEntry* entry);
|
||||
|
||||
void SetRevision(int64 revision);
|
||||
int64 GetRevision() const;
|
||||
|
||||
void SetDone(bool done);
|
||||
|
||||
bool GetRewind() const;
|
||||
|
||||
private:
|
||||
int32 fCookie;
|
||||
ShareDirEntry* fEntries[kRemoteShareDirIteratorCapacity];
|
||||
int32 fCapacity;
|
||||
int32 fCount;
|
||||
int32 fIndex;
|
||||
int64 fRevision;
|
||||
bool fDone;
|
||||
bool fRewind;
|
||||
};
|
||||
|
||||
// ShareDir
|
||||
class ShareDir : public ShareNode {
|
||||
public:
|
||||
ShareDir(Volume* volume, vnode_id id,
|
||||
const NodeInfo* nodeInfo);
|
||||
virtual ~ShareDir();
|
||||
|
||||
void UpdateEntryCreatedEventRevision(int64 revision);
|
||||
int64 GetEntryCreatedEventRevision() const;
|
||||
|
||||
void UpdateEntryRemovedEventRevision(int64 revision);
|
||||
int64 GetEntryRemovedEventRevision() const;
|
||||
|
||||
void SetComplete(bool complete);
|
||||
bool IsComplete() const;
|
||||
|
||||
void AddEntry(ShareDirEntry* entry);
|
||||
void RemoveEntry(ShareDirEntry* entry);
|
||||
|
||||
ShareDirEntry* GetFirstEntry() const;
|
||||
ShareDirEntry* GetNextEntry(ShareDirEntry* entry) const;
|
||||
|
||||
void AddDirIterator(LocalShareDirIterator* iterator);
|
||||
void RemoveDirIterator(
|
||||
LocalShareDirIterator* iterator);
|
||||
|
||||
private:
|
||||
DoublyLinkedList<ShareDirEntry> fEntries;
|
||||
DoublyLinkedList<LocalShareDirIterator> fIterators;
|
||||
int64 fEntryCreatedEventRevision;
|
||||
// The revision of the latest "created" or
|
||||
// "moved" (destination entry) event for
|
||||
// which the entry could not be created
|
||||
// (for whatever reason -- missing entry
|
||||
// info in the event request most likely).
|
||||
// To be compared with remote dir iterator
|
||||
// revisions to set fIsComplete.
|
||||
int64 fEntryRemovedEventRevision;
|
||||
// The revision of the latest "removed" or
|
||||
// "moved" (source entry) event. To be
|
||||
// compared with entry info revisions
|
||||
// returned by client request replies.
|
||||
// Such an info is to be considered invalid,
|
||||
// if its revision is less than this
|
||||
// revision, and must be reloaded from the
|
||||
// server.
|
||||
bool fIsComplete;
|
||||
};
|
||||
|
||||
#endif // NET_FS_SHARE_NODE_H
|
3111
src/add-ons/kernel/file_systems/netfs/client/ShareVolume.cpp
Normal file
3111
src/add-ons/kernel/file_systems/netfs/client/ShareVolume.cpp
Normal file
File diff suppressed because it is too large
Load Diff
247
src/add-ons/kernel/file_systems/netfs/client/ShareVolume.h
Normal file
247
src/add-ons/kernel/file_systems/netfs/client/ShareVolume.h
Normal file
@ -0,0 +1,247 @@
|
||||
// ShareVolume.h
|
||||
|
||||
#ifndef NET_FS_SHARE_VOLUME_H
|
||||
#define NET_FS_SHARE_VOLUME_H
|
||||
|
||||
#include <fsproto.h>
|
||||
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include "EntryInfo.h"
|
||||
#include "FSObject.h"
|
||||
#include "Locker.h"
|
||||
#include "RequestHandler.h"
|
||||
#include "RequestMemberArray.h"
|
||||
#include "ServerNodeID.h"
|
||||
#include "Volume.h"
|
||||
|
||||
class AttrDirInfo;
|
||||
class ExtendedServerInfo;
|
||||
class ExtendedShareInfo;
|
||||
class Node;
|
||||
class ReadQueryReply;
|
||||
class RemoteShareDirIterator;
|
||||
class RequestConnection;
|
||||
class RootShareVolume;
|
||||
class ServerConnection;
|
||||
class ServerConnectionProvider;
|
||||
class ShareAttrDirIterator;
|
||||
class ShareDir;
|
||||
class ShareDirEntry;
|
||||
class ShareNode;
|
||||
class WalkReply;
|
||||
|
||||
class ShareVolume : public Volume {
|
||||
public:
|
||||
ShareVolume(VolumeManager* volumeManager,
|
||||
ServerConnectionProvider*
|
||||
connectionProvider,
|
||||
ExtendedServerInfo* serverInfo,
|
||||
ExtendedShareInfo* shareInfo);
|
||||
~ShareVolume();
|
||||
|
||||
int32 GetID() const;
|
||||
|
||||
bool IsReadOnly() const;
|
||||
bool SupportsQueries() const;
|
||||
|
||||
status_t Init(const char* name);
|
||||
void Uninit();
|
||||
|
||||
virtual Node* GetRootNode() const;
|
||||
|
||||
virtual void PrepareToUnmount();
|
||||
|
||||
virtual void RemoveChildVolume(Volume* volume);
|
||||
|
||||
// FS
|
||||
virtual status_t Unmount();
|
||||
virtual status_t Sync();
|
||||
|
||||
// vnodes
|
||||
virtual status_t ReadVNode(vnode_id vnid, char reenter,
|
||||
Node** node);
|
||||
virtual status_t WriteVNode(Node* node, char reenter);
|
||||
virtual status_t RemoveVNode(Node* node, char reenter);
|
||||
|
||||
// nodes
|
||||
virtual status_t FSync(Node* node);
|
||||
virtual status_t ReadStat(Node* node, struct stat* st);
|
||||
virtual status_t WriteStat(Node* node, struct stat *st,
|
||||
uint32 mask);
|
||||
virtual status_t Access(Node* node, int mode);
|
||||
|
||||
// files
|
||||
virtual status_t Create(Node* dir, const char* name,
|
||||
int openMode, int mode, vnode_id* vnid,
|
||||
void** cookie);
|
||||
virtual status_t Open(Node* node, int openMode,
|
||||
void** cookie);
|
||||
virtual status_t Close(Node* node, void* cookie);
|
||||
virtual status_t FreeCookie(Node* node, void* cookie);
|
||||
virtual status_t Read(Node* node, void* cookie, off_t pos,
|
||||
void* buffer, size_t bufferSize,
|
||||
size_t* bytesRead);
|
||||
virtual status_t Write(Node* node, void* cookie, off_t pos,
|
||||
const void* buffer, size_t bufferSize,
|
||||
size_t* bytesWritten);
|
||||
|
||||
// hard links / symlinks
|
||||
virtual status_t Link(Node* dir, const char* name,
|
||||
Node* node);
|
||||
virtual status_t Unlink(Node* dir, const char* name);
|
||||
virtual status_t Symlink(Node* dir, const char* name,
|
||||
const char* target);
|
||||
virtual status_t ReadLink(Node* node, char* buffer,
|
||||
size_t bufferSize, size_t* bytesRead);
|
||||
virtual status_t Rename(Node* oldDir, const char* oldName,
|
||||
Node* newDir, const char* newName);
|
||||
|
||||
// directories
|
||||
virtual status_t MkDir(Node* dir, const char* name,
|
||||
int mode);
|
||||
virtual status_t RmDir(Node* dir, const char* name);
|
||||
virtual status_t OpenDir(Node* node, void** cookie);
|
||||
virtual status_t CloseDir(Node* node, void* cookie);
|
||||
virtual status_t FreeDirCookie(Node* node, void* cookie);
|
||||
virtual status_t ReadDir(Node* node, void* cookie,
|
||||
struct dirent* buffer, size_t bufferSize,
|
||||
int32 count, int32* countRead);
|
||||
virtual status_t RewindDir(Node* node, void* cookie);
|
||||
virtual status_t Walk(Node* dir, const char* entryName,
|
||||
char** resolvedPath, vnode_id* vnid);
|
||||
|
||||
// attributes
|
||||
virtual status_t OpenAttrDir(Node* node, void** cookie);
|
||||
virtual status_t CloseAttrDir(Node* node, void* cookie);
|
||||
virtual status_t FreeAttrDirCookie(Node* node,
|
||||
void* cookie);
|
||||
virtual status_t ReadAttrDir(Node* node, void* cookie,
|
||||
struct dirent* buffer, size_t bufferSize,
|
||||
int32 count, int32* countRead);
|
||||
virtual status_t RewindAttrDir(Node* node, void* cookie);
|
||||
virtual status_t ReadAttr(Node* node, const char* name,
|
||||
int type, off_t pos, void* buffer,
|
||||
size_t bufferSize, size_t* bytesRead);
|
||||
virtual status_t WriteAttr(Node* node, const char* name,
|
||||
int type, off_t pos, const void* buffer,
|
||||
size_t bufferSize, size_t* bytesWritten);
|
||||
virtual status_t RemoveAttr(Node* node, const char* name);
|
||||
virtual status_t RenameAttr(Node* node,
|
||||
const char* oldName, const char* newName);
|
||||
virtual status_t StatAttr(Node* node, const char* name,
|
||||
struct attr_info* attrInfo);
|
||||
|
||||
// queries
|
||||
status_t GetQueryEntry(const EntryInfo& entryInfo,
|
||||
const NodeInfo& dirInfo,
|
||||
struct dirent* buffer, size_t bufferSize,
|
||||
int32* countRead);
|
||||
|
||||
|
||||
// service methods called from "outside"
|
||||
void ProcessNodeMonitoringRequest(
|
||||
NodeMonitoringRequest* request);
|
||||
void ConnectionClosed();
|
||||
|
||||
private:
|
||||
struct NodeMap;
|
||||
struct EntryKey;
|
||||
struct EntryMap;
|
||||
struct LocalNodeIDMap;
|
||||
struct RemoteNodeIDMap;
|
||||
struct DirCookie;
|
||||
struct AttrDirCookie;
|
||||
struct AttrDirIteratorMap;
|
||||
|
||||
private:
|
||||
status_t _ReadRemoteDir(ShareDir* directory,
|
||||
RemoteShareDirIterator* remoteIterator);
|
||||
|
||||
void _HandleEntryCreatedRequest(
|
||||
EntryCreatedRequest* request);
|
||||
void _HandleEntryRemovedRequest(
|
||||
EntryRemovedRequest* request);
|
||||
void _HandleEntryMovedRequest(
|
||||
EntryMovedRequest* request);
|
||||
void _HandleStatChangedRequest(
|
||||
StatChangedRequest* request);
|
||||
void _HandleAttributeChangedRequest(
|
||||
AttributeChangedRequest* request);
|
||||
|
||||
status_t _GetLocalNodeID(NodeID remoteID, ino_t* localID,
|
||||
bool enter);
|
||||
status_t _GetRemoteNodeID(ino_t localID,
|
||||
NodeID* remoteID);
|
||||
void _RemoveLocalNodeID(ino_t localID);
|
||||
|
||||
ShareNode* _GetNodeByLocalID(ino_t localID);
|
||||
ShareNode* _GetNodeByRemoteID(NodeID remoteID);
|
||||
status_t _LoadNode(const NodeInfo& nodeInfo,
|
||||
ShareNode** node);
|
||||
status_t _UpdateNode(const NodeInfo& nodeInfo);
|
||||
|
||||
ShareDirEntry* _GetEntryByLocalID(ino_t localDirID,
|
||||
const char* name);
|
||||
ShareDirEntry* _GetEntryByRemoteID(NodeID remoteDirID,
|
||||
const char* name);
|
||||
status_t _LoadEntry(ShareDir* directory,
|
||||
const EntryInfo& entryInfo,
|
||||
ShareDirEntry** entry);
|
||||
void _RemoveEntry(ShareDirEntry* entry);
|
||||
bool _IsObsoleteEntryInfo(
|
||||
const EntryInfo& entryInfo);
|
||||
|
||||
status_t _AddAttrDirIterator(ShareNode* node,
|
||||
ShareAttrDirIterator* iterator);
|
||||
void _RemoveAttrDirIterator(ShareNode* node,
|
||||
ShareAttrDirIterator* iterator);
|
||||
status_t _LoadAttrDir(ShareNode* node,
|
||||
const AttrDirInfo& attrDirInfo);
|
||||
status_t _UpdateAttrDir(NodeID remoteID,
|
||||
const AttrDirInfo& attrDirInfo);
|
||||
|
||||
void _NodeRemoved(NodeID remoteID);
|
||||
void _EntryCreated(NodeID remoteDirID,
|
||||
const char* name,
|
||||
const EntryInfo* entryInfo, int64 revision);
|
||||
void _EntryRemoved(NodeID remoteDirID,
|
||||
const char* name, int64 revision);
|
||||
void _EntryMoved(NodeID remoteOldDirID,
|
||||
const char* oldName, NodeID remoteNewDirID,
|
||||
const char* name,
|
||||
const EntryInfo* entryInfo, int64 revision);
|
||||
|
||||
status_t _Walk(NodeID remoteDirID, const char* entryName,
|
||||
bool resolveLink, WalkReply** reply);
|
||||
status_t _MultiWalk(
|
||||
RequestMemberArray<EntryInfo>& entryInfos,
|
||||
MultiWalkReply** reply);
|
||||
status_t _Close(int32 cookie);
|
||||
|
||||
uint32 _GetConnectionState();
|
||||
bool _IsConnected();
|
||||
bool _EnsureShareMounted();
|
||||
status_t _MountShare();
|
||||
|
||||
private:
|
||||
int32 fID;
|
||||
uint32 fFlags;
|
||||
Locker fMountLock;
|
||||
ShareDir* fRootNode;
|
||||
NodeMap* fNodes; // local ID -> ShareNode
|
||||
EntryMap* fEntries; // local ID, name -> ShareDirEntry
|
||||
AttrDirIteratorMap* fAttrDirIterators;
|
||||
// local ID -> DoublyLinkedList<>
|
||||
LocalNodeIDMap* fLocalNodeIDs; // remote ID -> local ID
|
||||
RemoteNodeIDMap* fRemoteNodeIDs; // local ID -> remote ID
|
||||
ServerConnectionProvider* fServerConnectionProvider;
|
||||
ExtendedServerInfo* fServerInfo;
|
||||
ExtendedShareInfo* fShareInfo;
|
||||
ServerConnection* fServerConnection;
|
||||
RequestConnection* fConnection;
|
||||
uint32 fSharePermissions;
|
||||
uint32 fConnectionState;
|
||||
};
|
||||
|
||||
#endif // NET_FS_SHARE_VOLUME_H
|
314
src/add-ons/kernel/file_systems/netfs/client/VirtualDir.cpp
Normal file
314
src/add-ons/kernel/file_systems/netfs/client/VirtualDir.cpp
Normal file
@ -0,0 +1,314 @@
|
||||
// VirtualDir.cpp
|
||||
|
||||
#include "VirtualDir.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
// constructor
|
||||
VirtualDirEntry::VirtualDirEntry()
|
||||
: fName(),
|
||||
fNode(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
VirtualDirEntry::~VirtualDirEntry()
|
||||
{
|
||||
}
|
||||
|
||||
// SetTo
|
||||
status_t
|
||||
VirtualDirEntry::SetTo(const char* name, Node* node)
|
||||
{
|
||||
if (!name || strlen(name) == 0 || !node)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (!fName.SetTo(name))
|
||||
return B_NO_MEMORY;
|
||||
fNode = node;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// GetName
|
||||
const char*
|
||||
VirtualDirEntry::GetName() const
|
||||
{
|
||||
return fName.GetString();
|
||||
}
|
||||
|
||||
// GetNode
|
||||
Node*
|
||||
VirtualDirEntry::GetNode() const
|
||||
{
|
||||
return fNode;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
VirtualDirIterator::VirtualDirIterator()
|
||||
: fDirectory(NULL),
|
||||
fCurrentEntry(NULL),
|
||||
fState(STATE_DOT)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
VirtualDirIterator::~VirtualDirIterator()
|
||||
{
|
||||
SetDirectory(NULL);
|
||||
}
|
||||
|
||||
// SetDirectory
|
||||
void
|
||||
VirtualDirIterator::SetDirectory(VirtualDir* directory, bool onlyChildren)
|
||||
{
|
||||
// unset the old directory
|
||||
if (fDirectory)
|
||||
fDirectory->RemoveDirIterator(this);
|
||||
|
||||
// set the new directory
|
||||
fDirectory = directory;
|
||||
if (fDirectory) {
|
||||
fDirectory->AddDirIterator(this);
|
||||
|
||||
if (onlyChildren) {
|
||||
fCurrentEntry = fDirectory->GetFirstEntry();
|
||||
fState = STATE_OTHERS;
|
||||
} else {
|
||||
fCurrentEntry = NULL;
|
||||
fState = STATE_DOT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetCurrentEntry
|
||||
bool
|
||||
VirtualDirIterator::GetCurrentEntry(const char** name, Node** node)
|
||||
{
|
||||
if (!fDirectory)
|
||||
return false;
|
||||
switch (fState) {
|
||||
case STATE_DOT:
|
||||
*name = ".";
|
||||
*node = fDirectory;
|
||||
return true;
|
||||
case STATE_DOT_DOT:
|
||||
*name = "..";
|
||||
*node = fDirectory->GetParent();
|
||||
if (!*node)
|
||||
*node = fDirectory;
|
||||
return true;
|
||||
default:
|
||||
if (!fCurrentEntry)
|
||||
return false;
|
||||
*name = fCurrentEntry->GetName();
|
||||
*node = fCurrentEntry->GetNode();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// GetCurrentEntry
|
||||
VirtualDirEntry*
|
||||
VirtualDirIterator::GetCurrentEntry() const
|
||||
{
|
||||
return fCurrentEntry;
|
||||
}
|
||||
|
||||
// NextEntry
|
||||
void
|
||||
VirtualDirIterator::NextEntry()
|
||||
{
|
||||
if (!fDirectory)
|
||||
return;
|
||||
switch (fState) {
|
||||
case STATE_DOT:
|
||||
fState = STATE_DOT_DOT;
|
||||
break;
|
||||
case STATE_DOT_DOT:
|
||||
fState = STATE_OTHERS;
|
||||
fCurrentEntry = fDirectory->GetFirstEntry();
|
||||
break;
|
||||
default:
|
||||
if (fCurrentEntry)
|
||||
fCurrentEntry = fDirectory->GetNextEntry(fCurrentEntry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Rewind
|
||||
void
|
||||
VirtualDirIterator::Rewind()
|
||||
{
|
||||
fState = STATE_DOT;
|
||||
fCurrentEntry = NULL;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
VirtualDir::VirtualDir(Volume* volume, vnode_id nodeID)
|
||||
: Node(volume, nodeID),
|
||||
fParent(NULL),
|
||||
fCreationTime(0),
|
||||
fEntries(),
|
||||
fEntryList(),
|
||||
fIterators()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
VirtualDir::~VirtualDir()
|
||||
{
|
||||
while (VirtualDirEntry* entry = GetFirstEntry())
|
||||
RemoveEntry(entry->GetName());
|
||||
}
|
||||
|
||||
// InitCheck
|
||||
status_t
|
||||
VirtualDir::InitCheck() const
|
||||
{
|
||||
return fEntries.InitCheck();
|
||||
}
|
||||
|
||||
// SetParent
|
||||
void
|
||||
VirtualDir::SetParent(VirtualDir* parent)
|
||||
{
|
||||
fParent = parent;
|
||||
}
|
||||
|
||||
// GetParent
|
||||
VirtualDir*
|
||||
VirtualDir::GetParent() const
|
||||
{
|
||||
return fParent;
|
||||
}
|
||||
|
||||
// GetCreationTime
|
||||
time_t
|
||||
VirtualDir::GetCreationTime() const
|
||||
{
|
||||
return fCreationTime;
|
||||
}
|
||||
|
||||
// AddEntry
|
||||
status_t
|
||||
VirtualDir::AddEntry(const char* name, Node* child)
|
||||
{
|
||||
if (!name || !child || fEntries.ContainsKey(name))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// create an entry
|
||||
VirtualDirEntry* entry = new(std::nothrow) VirtualDirEntry;
|
||||
if (!entry)
|
||||
return B_NO_MEMORY;
|
||||
ObjectDeleter<VirtualDirEntry> entryDeleter(entry);
|
||||
status_t error = entry->SetTo(name, child);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// add the entry
|
||||
error = fEntries.Put(name, entry);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
fEntryList.Insert(entry);
|
||||
entryDeleter.Detach();
|
||||
|
||||
// TODO: That's not so nice. Check whether better to move the fParent
|
||||
// property to Node.
|
||||
if (VirtualDir* childDir = dynamic_cast<VirtualDir*>(child))
|
||||
childDir->SetParent(this);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// RemoveEntry
|
||||
Node*
|
||||
VirtualDir::RemoveEntry(const char* name)
|
||||
{
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
Node* child = NULL;
|
||||
VirtualDirEntry* entry = fEntries.Remove(name);
|
||||
if (entry) {
|
||||
child = entry->GetNode();
|
||||
// update the directory iterators pointing to the removed entry
|
||||
for (VirtualDirIterator* iterator = fIterators.First();
|
||||
iterator;
|
||||
iterator = fIterators.GetNext(iterator)) {
|
||||
if (iterator->GetCurrentEntry() == entry)
|
||||
iterator->NextEntry();
|
||||
}
|
||||
|
||||
// remove the entry completely
|
||||
fEntryList.Remove(entry);
|
||||
delete entry;
|
||||
|
||||
// TODO: See AddEntry().
|
||||
if (VirtualDir* childDir = dynamic_cast<VirtualDir*>(child))
|
||||
childDir->SetParent(NULL);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
// GetEntry
|
||||
VirtualDirEntry*
|
||||
VirtualDir::GetEntry(const char* name) const
|
||||
{
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
return fEntries.Get(name);
|
||||
}
|
||||
|
||||
// GetChildNode
|
||||
Node*
|
||||
VirtualDir::GetChildNode(const char* name) const
|
||||
{
|
||||
if (VirtualDirEntry* entry = GetEntry(name))
|
||||
return entry->GetNode();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// GetFirstEntry
|
||||
VirtualDirEntry*
|
||||
VirtualDir::GetFirstEntry() const
|
||||
{
|
||||
return fEntryList.First();
|
||||
}
|
||||
|
||||
// GetNextEntry
|
||||
VirtualDirEntry*
|
||||
VirtualDir::GetNextEntry(VirtualDirEntry* entry) const
|
||||
{
|
||||
if (!entry)
|
||||
return NULL;
|
||||
return fEntryList.GetNext(entry);
|
||||
}
|
||||
|
||||
// AddDirIterator
|
||||
void
|
||||
VirtualDir::AddDirIterator(VirtualDirIterator* iterator)
|
||||
{
|
||||
if (!iterator)
|
||||
return;
|
||||
|
||||
fIterators.Insert(iterator);
|
||||
}
|
||||
|
||||
// RemoveDirIterator
|
||||
void
|
||||
VirtualDir::RemoveDirIterator(VirtualDirIterator* iterator)
|
||||
{
|
||||
if (!iterator)
|
||||
return;
|
||||
|
||||
fIterators.Remove(iterator);
|
||||
}
|
92
src/add-ons/kernel/file_systems/netfs/client/VirtualDir.h
Normal file
92
src/add-ons/kernel/file_systems/netfs/client/VirtualDir.h
Normal file
@ -0,0 +1,92 @@
|
||||
// VirtualDir.h
|
||||
|
||||
#ifndef NET_FS_VIRTUAL_DIR_H
|
||||
#define NET_FS_VIRTUAL_DIR_H
|
||||
|
||||
#include <HashMap.h>
|
||||
#include <HashString.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include "Node.h"
|
||||
|
||||
class VirtualDir;
|
||||
class VirtualDirEntry;
|
||||
|
||||
// VirtualDirIterator
|
||||
class VirtualDirIterator : public DoublyLinkedListLinkImpl<VirtualDirIterator> {
|
||||
public:
|
||||
VirtualDirIterator();
|
||||
~VirtualDirIterator();
|
||||
|
||||
void SetDirectory(VirtualDir* directory,
|
||||
bool onlyChildren = false);
|
||||
|
||||
bool GetCurrentEntry(const char** name, Node** node);
|
||||
VirtualDirEntry* GetCurrentEntry() const;
|
||||
// for use by VirtualDir only
|
||||
void NextEntry();
|
||||
void Rewind();
|
||||
|
||||
private:
|
||||
enum {
|
||||
STATE_DOT = 0,
|
||||
STATE_DOT_DOT = 1,
|
||||
STATE_OTHERS = 2,
|
||||
};
|
||||
|
||||
VirtualDir* fDirectory;
|
||||
VirtualDirEntry* fCurrentEntry;
|
||||
int fState;
|
||||
};
|
||||
|
||||
// VirtualDirEntry
|
||||
class VirtualDirEntry : public DoublyLinkedListLinkImpl<VirtualDirEntry> {
|
||||
public:
|
||||
VirtualDirEntry();
|
||||
~VirtualDirEntry();
|
||||
|
||||
status_t SetTo(const char* name, Node* node);
|
||||
|
||||
const char* GetName() const;
|
||||
Node* GetNode() const;
|
||||
|
||||
private:
|
||||
HashString fName;
|
||||
Node* fNode;
|
||||
};
|
||||
|
||||
// VirtualDir
|
||||
class VirtualDir : public Node, public DoublyLinkedListLinkImpl<VirtualDir> {
|
||||
public:
|
||||
VirtualDir(Volume* volume, vnode_id nodeID);
|
||||
virtual ~VirtualDir();
|
||||
|
||||
status_t InitCheck() const;
|
||||
|
||||
void SetParent(VirtualDir* parent);
|
||||
VirtualDir* GetParent() const;
|
||||
// TODO: Remove? We don't need it, do we?
|
||||
|
||||
time_t GetCreationTime() const;
|
||||
|
||||
status_t AddEntry(const char* name, Node* child);
|
||||
Node* RemoveEntry(const char* name);
|
||||
VirtualDirEntry* GetEntry(const char* name) const;
|
||||
Node* GetChildNode(const char* name) const;
|
||||
VirtualDirEntry* GetFirstEntry() const;
|
||||
VirtualDirEntry* GetNextEntry(VirtualDirEntry* entry) const;
|
||||
|
||||
void AddDirIterator(VirtualDirIterator* iterator);
|
||||
void RemoveDirIterator(VirtualDirIterator* iterator);
|
||||
|
||||
private:
|
||||
typedef HashMap<HashString, VirtualDirEntry*> EntryMap;
|
||||
|
||||
VirtualDir* fParent;
|
||||
time_t fCreationTime;
|
||||
EntryMap fEntries;
|
||||
DoublyLinkedList<VirtualDirEntry> fEntryList;
|
||||
DoublyLinkedList<VirtualDirIterator> fIterators;
|
||||
};
|
||||
|
||||
#endif // NET_FS_VIRTUAL_DIR_H
|
839
src/add-ons/kernel/file_systems/netfs/client/VirtualVolume.cpp
Normal file
839
src/add-ons/kernel/file_systems/netfs/client/VirtualVolume.cpp
Normal file
@ -0,0 +1,839 @@
|
||||
// VirtualVolume.cpp
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "Compatibility.h"
|
||||
#include "DebugSupport.h"
|
||||
#include "QueryIterator.h"
|
||||
#include "QueryManager.h"
|
||||
#include "VirtualDir.h"
|
||||
#include "VirtualVolume.h"
|
||||
#include "VolumeManager.h"
|
||||
#include "VolumeSupport.h"
|
||||
|
||||
// constructor
|
||||
VirtualVolume::VirtualVolume(VolumeManager* volumeManager)
|
||||
: Volume(volumeManager),
|
||||
fRootNode(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
VirtualVolume::~VirtualVolume()
|
||||
{
|
||||
delete fRootNode;
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
VirtualVolume::Init(const char* name)
|
||||
{
|
||||
status_t error = Volume::Init(name);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// get an ID for the root node
|
||||
vnode_id rootNodeID = fVolumeManager->NewNodeID(this);
|
||||
if (rootNodeID < 0) {
|
||||
Uninit();
|
||||
return rootNodeID;
|
||||
}
|
||||
|
||||
// create the root node
|
||||
fRootNode = new(std::nothrow) VirtualDir(this, rootNodeID);
|
||||
if (!fRootNode) {
|
||||
Uninit();
|
||||
fVolumeManager->RemoveNodeID(rootNodeID);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
error = fRootNode->InitCheck();
|
||||
if (error != B_OK) {
|
||||
Uninit();
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Uninit
|
||||
void
|
||||
VirtualVolume::Uninit()
|
||||
{
|
||||
if (fRootNode) {
|
||||
fVolumeManager->RemoveNodeID(fRootNode->GetID());
|
||||
delete fRootNode;
|
||||
fRootNode = NULL;
|
||||
}
|
||||
|
||||
Volume::Uninit();
|
||||
}
|
||||
|
||||
// GetRootNode
|
||||
Node*
|
||||
VirtualVolume::GetRootNode() const
|
||||
{
|
||||
return fRootNode;
|
||||
}
|
||||
|
||||
// PrepareToUnmount
|
||||
void
|
||||
VirtualVolume::PrepareToUnmount()
|
||||
{
|
||||
Volume::PrepareToUnmount();
|
||||
|
||||
// remove all child volumes
|
||||
|
||||
// init a directory iterator
|
||||
fLock.Lock();
|
||||
VirtualDirIterator iterator;
|
||||
iterator.SetDirectory(fRootNode, true);
|
||||
|
||||
// iterate through the directory
|
||||
const char* name;
|
||||
Node* node;
|
||||
while (iterator.GetCurrentEntry(&name, &node)) {
|
||||
iterator.NextEntry();
|
||||
Volume* volume = fVolumeManager->GetVolume(node->GetID());
|
||||
fLock.Unlock();
|
||||
if (volume) {
|
||||
RemoveChildVolume(volume);
|
||||
volume->SetUnmounting(true);
|
||||
volume->PutVolume();
|
||||
}
|
||||
fLock.Lock();
|
||||
}
|
||||
|
||||
// uninit the directory iterator
|
||||
iterator.SetDirectory(NULL);
|
||||
|
||||
// remove the our root node
|
||||
vnode_id rootNodeID = fRootNode->GetID();
|
||||
|
||||
fLock.Unlock();
|
||||
|
||||
if (GetVNode(rootNodeID, &node) == B_OK) {
|
||||
Volume::RemoveVNode(rootNodeID);
|
||||
PutVNode(rootNodeID);
|
||||
}
|
||||
}
|
||||
|
||||
// AddChildVolume
|
||||
status_t
|
||||
VirtualVolume::AddChildVolume(Volume* volume)
|
||||
{
|
||||
if (!volume)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// don't add anything, if we are already unmounting
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
if (fUnmounting)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// get and check the node name
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
int32 nameLen = strlen(volume->GetName());
|
||||
if (nameLen == 0 || nameLen >= B_FILE_NAME_LENGTH)
|
||||
return B_BAD_VALUE;
|
||||
strcpy(name, volume->GetName());
|
||||
|
||||
// add the volume's root node
|
||||
status_t error = fRootNode->AddEntry(name, volume->GetRootNode());
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// set the volume's parent volume
|
||||
volume->SetParentVolume(this);
|
||||
AddReference();
|
||||
|
||||
// send out a notification
|
||||
vnode_id dirID = fRootNode->GetID();
|
||||
vnode_id nodeID = volume->GetRootID();
|
||||
locker.Unlock();
|
||||
NotifyListener(B_ENTRY_CREATED, fVolumeManager->GetID(), dirID, 0, nodeID,
|
||||
name);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// RemoveChildVolume
|
||||
void
|
||||
VirtualVolume::RemoveChildVolume(Volume* volume)
|
||||
{
|
||||
if (!volume)
|
||||
return;
|
||||
|
||||
// check, if the volume's root node is a child of our root node
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
Node* node = fRootNode->GetChildNode(volume->GetName());
|
||||
if (!node)
|
||||
return;
|
||||
if (node != volume->GetRootNode())
|
||||
return;
|
||||
|
||||
// remove it
|
||||
fRootNode->RemoveEntry(volume->GetName());
|
||||
volume->SetParentVolume(NULL);
|
||||
|
||||
// get the data needed for the node monitoring notification
|
||||
vnode_id dirID = fRootNode->GetID();
|
||||
vnode_id nodeID = volume->GetRootID();
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
strcpy(name, volume->GetName());
|
||||
|
||||
// surrender the child volumes reference to us
|
||||
// Since the caller of this method must have a valid reference to us,
|
||||
// this is unproblematic, even if fLock is being held, while this method
|
||||
// is invoked.
|
||||
locker.Unlock();
|
||||
PutVolume();
|
||||
|
||||
// send out a notification
|
||||
locker.Unlock();
|
||||
NotifyListener(B_ENTRY_REMOVED, fVolumeManager->GetID(), dirID, 0, nodeID,
|
||||
name);
|
||||
}
|
||||
|
||||
// GetChildVolume
|
||||
Volume*
|
||||
VirtualVolume::GetChildVolume(const char* name)
|
||||
{
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
// get the child node of the root node
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
Node* node = fRootNode->GetChildNode(name);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
// get its volume, if it is the root volume
|
||||
Volume* volume = node->GetVolume();
|
||||
if (volume->GetRootNode() != node)
|
||||
return NULL;
|
||||
locker.Unlock();
|
||||
|
||||
return fVolumeManager->GetVolume(node->GetID());
|
||||
}
|
||||
|
||||
// GetUniqueEntryName
|
||||
status_t
|
||||
VirtualVolume::GetUniqueEntryName(const char* baseName, char* buffer)
|
||||
{
|
||||
if (!baseName || !buffer)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// check the base name len
|
||||
int32 baseLen = strlen(baseName);
|
||||
if (baseLen == 0 || baseLen >= B_FILE_NAME_LENGTH)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
strcpy(buffer, baseName);
|
||||
|
||||
AutoLocker<Locker> _(fLock);
|
||||
|
||||
// adjust the name, if necessary
|
||||
int32 suffixNumber = 2;
|
||||
while (fRootNode->GetChildNode(baseName)) {
|
||||
// create a suffix
|
||||
char suffix[13];
|
||||
sprintf(suffix, " %ld", suffixNumber);
|
||||
suffixNumber++;
|
||||
|
||||
// check the len
|
||||
int32 suffixLen = strlen(suffix);
|
||||
if (baseLen + suffixLen >= B_FILE_NAME_LENGTH)
|
||||
return B_NAME_TOO_LONG;
|
||||
|
||||
// compose the final name
|
||||
strcpy(buffer + baseLen, suffix);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- FS -----
|
||||
|
||||
// Unmount
|
||||
status_t
|
||||
VirtualVolume::Unmount()
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Sync
|
||||
status_t
|
||||
VirtualVolume::Sync()
|
||||
{
|
||||
// TODO: Recursively call Sync().
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- vnodes -----
|
||||
|
||||
// ReadVNode
|
||||
status_t
|
||||
VirtualVolume::ReadVNode(vnode_id vnid, char reenter, Node** node)
|
||||
{
|
||||
if (vnid != GetRootID())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
AutoLocker<Locker> _(fLock);
|
||||
fRootNode->SetKnownToVFS(true);
|
||||
*node = fRootNode;
|
||||
|
||||
// add a volume reference for the node
|
||||
AddReference();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// WriteVNode
|
||||
status_t
|
||||
VirtualVolume::WriteVNode(Node* node, char reenter)
|
||||
{
|
||||
if (node != fRootNode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
fRootNode->SetKnownToVFS(false);
|
||||
|
||||
// surrender the volume reference of the node
|
||||
locker.Unlock();
|
||||
PutVolume();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// RemoveVNode
|
||||
status_t
|
||||
VirtualVolume::RemoveVNode(Node* node, char reenter)
|
||||
{
|
||||
if (node != fRootNode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
fRootNode->SetKnownToVFS(false);
|
||||
|
||||
// surrender the volume reference of the node
|
||||
locker.Unlock();
|
||||
PutVolume();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- nodes -----
|
||||
|
||||
// FSync
|
||||
status_t
|
||||
VirtualVolume::FSync(Node* node)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// ReadStat
|
||||
status_t
|
||||
VirtualVolume::ReadStat(Node* node, struct stat* st)
|
||||
{
|
||||
if (node != fRootNode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
AutoLocker<Locker> _(fLock);
|
||||
st->st_ino = node->GetID();
|
||||
st->st_mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH
|
||||
| S_IXOTH;
|
||||
st->st_nlink = 1;
|
||||
st->st_size = 1;
|
||||
st->st_blksize = 1024;
|
||||
st->st_crtime = fRootNode->GetCreationTime();
|
||||
st->st_ctime = st->st_mtime = st->st_atime = st->st_crtime;
|
||||
st->st_dev = fVolumeManager->GetID();
|
||||
// we set the UID/GID fields to the one who mounted the FS
|
||||
st->st_uid = fVolumeManager->GetMountUID();
|
||||
st->st_gid = fVolumeManager->GetMountGID();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// WriteStat
|
||||
status_t
|
||||
VirtualVolume::WriteStat(Node* node, struct stat *st, uint32 mask)
|
||||
{
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// Access
|
||||
status_t
|
||||
VirtualVolume::Access(Node* node, int mode)
|
||||
{
|
||||
// TODO: Implement!
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- files -----
|
||||
|
||||
// Create
|
||||
status_t
|
||||
VirtualVolume::Create(Node* dir, const char* name, int openMode, int mode,
|
||||
vnode_id* vnid, void** cookie)
|
||||
{
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// Open
|
||||
status_t
|
||||
VirtualVolume::Open(Node* node, int openMode, void** cookie)
|
||||
{
|
||||
if (node != fRootNode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// we're read-only
|
||||
if ((openMode & O_RWMASK) == O_WRONLY)
|
||||
return B_PERMISSION_DENIED;
|
||||
if (openMode & O_TRUNC)
|
||||
return B_PERMISSION_DENIED;
|
||||
if ((openMode & O_RWMASK) == O_RDWR)
|
||||
openMode = (openMode & ~O_RWMASK) | O_RDONLY;
|
||||
|
||||
// set the result
|
||||
*cookie = NULL;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Close
|
||||
status_t
|
||||
VirtualVolume::Close(Node* node, void* cookie)
|
||||
{
|
||||
// no-op: FreeCookie() does the job
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// FreeCookie
|
||||
status_t
|
||||
VirtualVolume::FreeCookie(Node* node, void* cookie)
|
||||
{
|
||||
// nothing to do: we didn't allocate anything
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Read
|
||||
status_t
|
||||
VirtualVolume::Read(Node* node, void* cookie, off_t pos, void* _buffer,
|
||||
size_t bufferSize, size_t* _bytesRead)
|
||||
{
|
||||
// can't read() directories
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// Write
|
||||
status_t
|
||||
VirtualVolume::Write(Node* node, void* cookie, off_t pos, const void* _buffer,
|
||||
size_t bufferSize, size_t* bytesWritten)
|
||||
{
|
||||
// can't write() directories
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// IOCtl
|
||||
status_t
|
||||
VirtualVolume::IOCtl(Node* node, void* cookie, int cmd, void* buffer,
|
||||
size_t bufferSize)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// SetFlags
|
||||
status_t
|
||||
VirtualVolume::SetFlags(Node* node, void* cookie, int flags)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- hard links / symlinks -----
|
||||
|
||||
// Link
|
||||
status_t
|
||||
VirtualVolume::Link(Node* dir, const char* name, Node* node)
|
||||
{
|
||||
// we're read-only
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// Unlink
|
||||
status_t
|
||||
VirtualVolume::Unlink(Node* dir, const char* name)
|
||||
{
|
||||
// we're read-only
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// Symlink
|
||||
status_t
|
||||
VirtualVolume::Symlink(Node* dir, const char* name, const char* target)
|
||||
{
|
||||
// we're read-only
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// ReadLink
|
||||
status_t
|
||||
VirtualVolume::ReadLink(Node* node, char* buffer, size_t bufferSize,
|
||||
size_t* bytesRead)
|
||||
{
|
||||
// there are no symlinks
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Rename
|
||||
status_t
|
||||
VirtualVolume::Rename(Node* oldDir, const char* oldName, Node* newDir,
|
||||
const char* newName)
|
||||
{
|
||||
// we're read-only
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- directories -----
|
||||
|
||||
// MkDir
|
||||
status_t
|
||||
VirtualVolume::MkDir(Node* dir, const char* name, int mode)
|
||||
{
|
||||
// we're read-only
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// RmDir
|
||||
status_t
|
||||
VirtualVolume::RmDir(Node* dir, const char* name)
|
||||
{
|
||||
// we're read-only
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// OpenDir
|
||||
status_t
|
||||
VirtualVolume::OpenDir(Node* node, void** cookie)
|
||||
{
|
||||
if (node != fRootNode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// allocate an iterator
|
||||
VirtualDirIterator* iterator = new(std::nothrow) VirtualDirIterator;
|
||||
if (!iterator)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
iterator->SetDirectory(fRootNode);
|
||||
*cookie = iterator;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// CloseDir
|
||||
status_t
|
||||
VirtualVolume::CloseDir(Node* node, void* cookie)
|
||||
{
|
||||
// no-op: FreeDirCookie() does the job
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// FreeDirCookie
|
||||
status_t
|
||||
VirtualVolume::FreeDirCookie(Node* node, void* cookie)
|
||||
{
|
||||
if (node != fRootNode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// delete the iterator
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
VirtualDirIterator* iterator = (VirtualDirIterator*)cookie;
|
||||
delete iterator;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// ReadDir
|
||||
status_t
|
||||
VirtualVolume::ReadDir(Node* node, void* cookie, struct dirent* buffer,
|
||||
size_t bufferSize, int32 count, int32* countRead)
|
||||
{
|
||||
if (node != fRootNode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
*countRead = 0;
|
||||
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
VirtualDirIterator* iterator = (VirtualDirIterator*)cookie;
|
||||
|
||||
// get the current entry
|
||||
const char* name;
|
||||
Node* child;
|
||||
if (!iterator->GetCurrentEntry(&name, &child))
|
||||
return B_OK;
|
||||
|
||||
// set the name: this also checks the size of the buffer
|
||||
status_t error = set_dirent_name(buffer, bufferSize, name, strlen(name));
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// fill in the other fields
|
||||
buffer->d_pdev = fVolumeManager->GetID();
|
||||
buffer->d_pino = fRootNode->GetID();
|
||||
buffer->d_dev = fVolumeManager->GetID();
|
||||
buffer->d_ino = child->GetID();
|
||||
*countRead = 1;
|
||||
|
||||
// fix d_ino, if this is the parent of the root node
|
||||
if (strcmp(name, "..") == 0) {
|
||||
if (Volume* parentVolume = GetParentVolume())
|
||||
buffer->d_ino = parentVolume->GetRootID();
|
||||
}
|
||||
|
||||
iterator->NextEntry();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// RewindDir
|
||||
status_t
|
||||
VirtualVolume::RewindDir(Node* node, void* cookie)
|
||||
{
|
||||
if (node != fRootNode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
VirtualDirIterator* iterator = (VirtualDirIterator*)cookie;
|
||||
iterator->Rewind();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Walk
|
||||
status_t
|
||||
VirtualVolume::Walk(Node* dir, const char* entryName, char** resolvedPath,
|
||||
vnode_id* vnid)
|
||||
{
|
||||
if (dir != fRootNode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// get the referred to node ID
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
if (strcmp(entryName, ".") == 0) {
|
||||
*vnid = dir->GetID();
|
||||
} else if (strcmp(entryName, "..") == 0) {
|
||||
if (Volume* parentVolume = GetParentVolume())
|
||||
*vnid = parentVolume->GetRootID();
|
||||
else
|
||||
*vnid = dir->GetID();
|
||||
} else {
|
||||
Node* node = fRootNode->GetChildNode(entryName);
|
||||
if (!node)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
*vnid = node->GetID();
|
||||
}
|
||||
locker.Unlock();
|
||||
|
||||
// get a VFS node reference
|
||||
Node* dummyNode;
|
||||
status_t error = GetVNode(*vnid, &dummyNode);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- attributes -----
|
||||
|
||||
// OpenAttrDir
|
||||
status_t
|
||||
VirtualVolume::OpenAttrDir(Node* node, void** cookie)
|
||||
{
|
||||
if (node != fRootNode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// we support no attributes at this time
|
||||
*cookie = NULL;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// CloseAttrDir
|
||||
status_t
|
||||
VirtualVolume::CloseAttrDir(Node* node, void* cookie)
|
||||
{
|
||||
// no-op: FreeAttrDirCookie() does the job
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// FreeAttrDirCookie
|
||||
status_t
|
||||
VirtualVolume::FreeAttrDirCookie(Node* node, void* _cookie)
|
||||
{
|
||||
// nothing to do: we didn't allocate anything
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// ReadAttrDir
|
||||
status_t
|
||||
VirtualVolume::ReadAttrDir(Node* node, void* _cookie, struct dirent* buffer,
|
||||
size_t bufferSize, int32 count, int32* countRead)
|
||||
{
|
||||
// no attributes for the time being
|
||||
*countRead = 0;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// RewindAttrDir
|
||||
status_t
|
||||
VirtualVolume::RewindAttrDir(Node* node, void* _cookie)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// ReadAttr
|
||||
status_t
|
||||
VirtualVolume::ReadAttr(Node* node, const char* name, int type, off_t pos,
|
||||
void* _buffer, size_t bufferSize, size_t* bytesRead)
|
||||
{
|
||||
// no attributes for the time being
|
||||
*bytesRead = 0;
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
// WriteAttr
|
||||
status_t
|
||||
VirtualVolume::WriteAttr(Node* node, const char* name, int type, off_t pos,
|
||||
const void* _buffer, size_t bufferSize, size_t* bytesWritten)
|
||||
{
|
||||
// no attributes for the time being
|
||||
*bytesWritten = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// RemoveAttr
|
||||
status_t
|
||||
VirtualVolume::RemoveAttr(Node* node, const char* name)
|
||||
{
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// RenameAttr
|
||||
status_t
|
||||
VirtualVolume::RenameAttr(Node* node, const char* oldName, const char* newName)
|
||||
{
|
||||
// no attributes for the time being
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
// StatAttr
|
||||
status_t
|
||||
VirtualVolume::StatAttr(Node* node, const char* name, struct attr_info* attrInfo)
|
||||
{
|
||||
// no attributes for the time being
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- queries -----
|
||||
|
||||
// OpenQuery
|
||||
status_t
|
||||
VirtualVolume::OpenQuery(const char* queryString, uint32 flags, port_id port,
|
||||
int32 token, QueryIterator** _iterator)
|
||||
{
|
||||
QueryManager* queryManager = fVolumeManager->GetQueryManager();
|
||||
|
||||
// allocate a hierarchical iterator
|
||||
HierarchicalQueryIterator* iterator
|
||||
= new(std::nothrow) HierarchicalQueryIterator(this);
|
||||
if (!iterator)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// add it to the query manager
|
||||
status_t error = queryManager->AddIterator(iterator);
|
||||
if (error != B_OK) {
|
||||
delete iterator;
|
||||
return error;
|
||||
}
|
||||
QueryIteratorPutter iteratorPutter(queryManager, iterator);
|
||||
|
||||
// iterate through the child volumes and open subqueries for them
|
||||
// init a directory iterator
|
||||
fLock.Lock();
|
||||
VirtualDirIterator dirIterator;
|
||||
dirIterator.SetDirectory(fRootNode, true);
|
||||
|
||||
// iterate through the directory
|
||||
const char* name;
|
||||
Node* node;
|
||||
while (dirIterator.GetCurrentEntry(&name, &node)) {
|
||||
dirIterator.NextEntry();
|
||||
Volume* volume = fVolumeManager->GetVolume(node->GetID());
|
||||
fLock.Unlock();
|
||||
|
||||
// open the subquery
|
||||
QueryIterator* subIterator;
|
||||
if (volume->OpenQuery(queryString, flags, port, token,
|
||||
&subIterator) == B_OK) {
|
||||
// add the subiterator
|
||||
if (queryManager->AddSubIterator(iterator, subIterator) != B_OK)
|
||||
queryManager->PutIterator(subIterator);
|
||||
}
|
||||
volume->PutVolume();
|
||||
|
||||
fLock.Lock();
|
||||
}
|
||||
|
||||
// uninit the directory iterator
|
||||
dirIterator.SetDirectory(NULL);
|
||||
fLock.Unlock();
|
||||
|
||||
// return the result
|
||||
*_iterator = iterator;
|
||||
iteratorPutter.Detach();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// FreeQueryIterator
|
||||
void
|
||||
VirtualVolume::FreeQueryIterator(QueryIterator* iterator)
|
||||
{
|
||||
delete iterator;
|
||||
}
|
||||
|
||||
// ReadQuery
|
||||
status_t
|
||||
VirtualVolume::ReadQuery(QueryIterator* _iterator, struct dirent* buffer,
|
||||
size_t bufferSize, int32 count, int32* countRead)
|
||||
{
|
||||
HierarchicalQueryIterator* iterator
|
||||
= dynamic_cast<HierarchicalQueryIterator*>(_iterator);
|
||||
|
||||
QueryManager* queryManager = fVolumeManager->GetQueryManager();
|
||||
while (QueryIterator* subIterator
|
||||
= queryManager->GetCurrentSubIterator(iterator)) {
|
||||
QueryIteratorPutter _(queryManager, subIterator);
|
||||
|
||||
status_t error = subIterator->GetVolume()->ReadQuery(subIterator,
|
||||
buffer, bufferSize, count, countRead);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
if (*countRead > 0)
|
||||
return B_OK;
|
||||
|
||||
queryManager->NextSubIterator(iterator, subIterator);
|
||||
}
|
||||
|
||||
*countRead = 0;
|
||||
return B_OK;
|
||||
}
|
||||
|
128
src/add-ons/kernel/file_systems/netfs/client/VirtualVolume.h
Normal file
128
src/add-ons/kernel/file_systems/netfs/client/VirtualVolume.h
Normal file
@ -0,0 +1,128 @@
|
||||
// VirtualVolume.h
|
||||
|
||||
#ifndef NET_FS_VIRTUAL_VOLUME_H
|
||||
#define NET_FS_VIRTUAL_VOLUME_H
|
||||
|
||||
#include <fsproto.h>
|
||||
|
||||
#include "Locker.h"
|
||||
#include "VirtualDir.h"
|
||||
#include "Volume.h"
|
||||
|
||||
class VirtualNode;
|
||||
|
||||
class VirtualVolume : public Volume {
|
||||
public:
|
||||
VirtualVolume(VolumeManager* volumeManager);
|
||||
~VirtualVolume();
|
||||
|
||||
status_t Init(const char* name);
|
||||
void Uninit();
|
||||
|
||||
virtual Node* GetRootNode() const;
|
||||
|
||||
virtual void PrepareToUnmount();
|
||||
|
||||
virtual status_t AddChildVolume(Volume* volume);
|
||||
virtual void RemoveChildVolume(Volume* volume);
|
||||
virtual Volume* GetChildVolume(const char* name);
|
||||
|
||||
status_t GetUniqueEntryName(const char* baseName,
|
||||
char* buffer);
|
||||
|
||||
// FS
|
||||
virtual status_t Unmount();
|
||||
virtual status_t Sync();
|
||||
|
||||
// vnodes
|
||||
virtual status_t ReadVNode(vnode_id vnid, char reenter,
|
||||
Node** node);
|
||||
virtual status_t WriteVNode(Node* node, char reenter);
|
||||
virtual status_t RemoveVNode(Node* node, char reenter);
|
||||
|
||||
// nodes
|
||||
virtual status_t FSync(Node* node);
|
||||
virtual status_t ReadStat(Node* node, struct stat* st);
|
||||
virtual status_t WriteStat(Node* node, struct stat *st,
|
||||
uint32 mask);
|
||||
virtual status_t Access(Node* node, int mode);
|
||||
|
||||
// files
|
||||
virtual status_t Create(Node* dir, const char* name,
|
||||
int openMode, int mode, vnode_id* vnid,
|
||||
void** cookie);
|
||||
virtual status_t Open(Node* node, int openMode,
|
||||
void** cookie);
|
||||
virtual status_t Close(Node* node, void* cookie);
|
||||
virtual status_t FreeCookie(Node* node, void* cookie);
|
||||
virtual status_t Read(Node* node, void* cookie, off_t pos,
|
||||
void* buffer, size_t bufferSize,
|
||||
size_t* bytesRead);
|
||||
virtual status_t Write(Node* node, void* cookie, off_t pos,
|
||||
const void* buffer, size_t bufferSize,
|
||||
size_t* bytesWritten);
|
||||
virtual status_t IOCtl(Node* node, void* cookie, int cmd,
|
||||
void* buffer, size_t bufferSize);
|
||||
virtual status_t SetFlags(Node* node, void* cookie,
|
||||
int flags);
|
||||
|
||||
// hard links / symlinks
|
||||
virtual status_t Link(Node* dir, const char* name,
|
||||
Node* node);
|
||||
virtual status_t Unlink(Node* dir, const char* name);
|
||||
virtual status_t Symlink(Node* dir, const char* name,
|
||||
const char* target);
|
||||
virtual status_t ReadLink(Node* node, char* buffer,
|
||||
size_t bufferSize, size_t* bytesRead);
|
||||
virtual status_t Rename(Node* oldDir, const char* oldName,
|
||||
Node* newDir, const char* newName);
|
||||
|
||||
// directories
|
||||
virtual status_t MkDir(Node* dir, const char* name,
|
||||
int mode);
|
||||
virtual status_t RmDir(Node* dir, const char* name);
|
||||
virtual status_t OpenDir(Node* node, void** cookie);
|
||||
virtual status_t CloseDir(Node* node, void* cookie);
|
||||
virtual status_t FreeDirCookie(Node* node, void* cookie);
|
||||
virtual status_t ReadDir(Node* node, void* cookie,
|
||||
struct dirent* buffer, size_t bufferSize,
|
||||
int32 count, int32* countRead);
|
||||
virtual status_t RewindDir(Node* node, void* cookie);
|
||||
virtual status_t Walk(Node* dir, const char* entryName,
|
||||
char** resolvedPath, vnode_id* vnid);
|
||||
|
||||
// attributes
|
||||
virtual status_t OpenAttrDir(Node* node, void** cookie);
|
||||
virtual status_t CloseAttrDir(Node* node, void* cookie);
|
||||
virtual status_t FreeAttrDirCookie(Node* node,
|
||||
void* cookie);
|
||||
virtual status_t ReadAttrDir(Node* node, void* cookie,
|
||||
struct dirent* buffer, size_t bufferSize,
|
||||
int32 count, int32* countRead);
|
||||
virtual status_t RewindAttrDir(Node* node, void* cookie);
|
||||
virtual status_t ReadAttr(Node* node, const char* name,
|
||||
int type, off_t pos, void* buffer,
|
||||
size_t bufferSize, size_t* bytesRead);
|
||||
virtual status_t WriteAttr(Node* node, const char* name,
|
||||
int type, off_t pos, const void* buffer,
|
||||
size_t bufferSize, size_t* bytesWritten);
|
||||
virtual status_t RemoveAttr(Node* node, const char* name);
|
||||
virtual status_t RenameAttr(Node* node,
|
||||
const char* oldName, const char* newName);
|
||||
virtual status_t StatAttr(Node* node, const char* name,
|
||||
struct attr_info* attrInfo);
|
||||
|
||||
// queries
|
||||
virtual status_t OpenQuery(const char* queryString,
|
||||
uint32 flags, port_id port, int32 token,
|
||||
QueryIterator** iterator);
|
||||
virtual void FreeQueryIterator(QueryIterator* iterator);
|
||||
virtual status_t ReadQuery(QueryIterator* iterator,
|
||||
struct dirent* buffer, size_t bufferSize,
|
||||
int32 count, int32* countRead);
|
||||
|
||||
protected:
|
||||
VirtualDir* fRootNode;
|
||||
};
|
||||
|
||||
#endif // NET_FS_VIRTUAL_VOLUME_H
|
546
src/add-ons/kernel/file_systems/netfs/client/Volume.cpp
Normal file
546
src/add-ons/kernel/file_systems/netfs/client/Volume.cpp
Normal file
@ -0,0 +1,546 @@
|
||||
// Volume.cpp
|
||||
|
||||
#include "Volume.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "Compatibility.h"
|
||||
#include "DebugSupport.h"
|
||||
#include "Node.h"
|
||||
#include "QueryManager.h"
|
||||
#include "VolumeManager.h"
|
||||
|
||||
// constructor
|
||||
Volume::Volume(VolumeManager* volumeManager)
|
||||
: FSObject(),
|
||||
fLock("volume"),
|
||||
fVolumeManager(volumeManager),
|
||||
fParentVolume(NULL),
|
||||
fName(),
|
||||
fUnmounting(false)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
Volume::~Volume()
|
||||
{
|
||||
}
|
||||
|
||||
// GetVolumeManager
|
||||
VolumeManager*
|
||||
Volume::GetVolumeManager() const
|
||||
{
|
||||
return fVolumeManager;
|
||||
}
|
||||
|
||||
// SetParentVolume
|
||||
void
|
||||
Volume::SetParentVolume(Volume* parent)
|
||||
{
|
||||
AutoLocker<Locker> _(fLock);
|
||||
fParentVolume = parent;
|
||||
}
|
||||
|
||||
// GetParentVolume
|
||||
Volume*
|
||||
Volume::GetParentVolume() const
|
||||
{
|
||||
return fParentVolume;
|
||||
}
|
||||
|
||||
// PutVolume
|
||||
void
|
||||
Volume::PutVolume()
|
||||
{
|
||||
fVolumeManager->PutVolume(this);
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
Volume::Init(const char* name)
|
||||
{
|
||||
if (!name || strlen(name) == 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (!fName.SetTo(name))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Uninit
|
||||
void
|
||||
Volume::Uninit()
|
||||
{
|
||||
}
|
||||
|
||||
// GetName
|
||||
const char*
|
||||
Volume::GetName() const
|
||||
{
|
||||
return fName.GetString();
|
||||
}
|
||||
|
||||
// GetRootID
|
||||
vnode_id
|
||||
Volume::GetRootID() const
|
||||
{
|
||||
return GetRootNode()->GetID();
|
||||
}
|
||||
|
||||
// SetUnmounting
|
||||
void
|
||||
Volume::SetUnmounting(bool unmounting)
|
||||
{
|
||||
fUnmounting = unmounting;
|
||||
}
|
||||
|
||||
// IsUnmounting
|
||||
bool
|
||||
Volume::IsUnmounting() const
|
||||
{
|
||||
return fUnmounting;
|
||||
}
|
||||
|
||||
// HandleEvent
|
||||
void
|
||||
Volume::HandleEvent(VolumeEvent* event)
|
||||
{
|
||||
}
|
||||
|
||||
// PrepareToUnmount
|
||||
void
|
||||
Volume::PrepareToUnmount()
|
||||
{
|
||||
fVolumeManager->GetQueryManager()->VolumeUnmounting(this);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- client methods -----
|
||||
|
||||
// GetVNode
|
||||
status_t
|
||||
Volume::GetVNode(vnode_id vnid, Node** node)
|
||||
{
|
||||
return get_vnode(fVolumeManager->GetID(), vnid, (void**)node);
|
||||
}
|
||||
|
||||
// PutVNode
|
||||
status_t
|
||||
Volume::PutVNode(vnode_id vnid)
|
||||
{
|
||||
return put_vnode(fVolumeManager->GetID(), vnid);
|
||||
}
|
||||
|
||||
// NewVNode
|
||||
status_t
|
||||
Volume::NewVNode(vnode_id vnid, Node* node)
|
||||
{
|
||||
status_t error = new_vnode(fVolumeManager->GetID(), vnid, node);
|
||||
if (error == B_OK)
|
||||
node->SetKnownToVFS(true);
|
||||
return error;
|
||||
}
|
||||
|
||||
// RemoveVNode
|
||||
status_t
|
||||
Volume::RemoveVNode(vnode_id vnid)
|
||||
{
|
||||
return remove_vnode(fVolumeManager->GetID(), vnid);
|
||||
}
|
||||
|
||||
// UnremoveVNode
|
||||
status_t
|
||||
Volume::UnremoveVNode(vnode_id vnid)
|
||||
{
|
||||
return unremove_vnode(fVolumeManager->GetID(), vnid);
|
||||
}
|
||||
|
||||
// IsVNodeRemoved
|
||||
int
|
||||
Volume::IsVNodeRemoved(vnode_id vnid)
|
||||
{
|
||||
return is_vnode_removed(fVolumeManager->GetID(), vnid);
|
||||
}
|
||||
|
||||
// SendNotification
|
||||
int
|
||||
Volume::SendNotification(port_id port, int32 token, uint32 what, int32 op,
|
||||
nspace_id nsida, nspace_id nsidb, vnode_id vnida, vnode_id vnidb,
|
||||
vnode_id vnidc, const char *name)
|
||||
{
|
||||
PRINT(("Volume::SendNotification(%ld, %ld, 0x%lx, 0x%lx, %ld, %ld, %lld, %lld, %lld, \"%s\")\n", port, token, what, op, nsida, nsidb, vnida, vnidb, vnidc, name));
|
||||
return send_notification(port, token, what, op, nsida, nsidb, vnida,
|
||||
vnidb, vnidc, name);
|
||||
}
|
||||
|
||||
// NotifyListener
|
||||
int
|
||||
Volume::NotifyListener(int32 opcode, nspace_id nsid, vnode_id vnida,
|
||||
vnode_id vnidb, vnode_id vnidc, const char *name)
|
||||
{
|
||||
return notify_listener(opcode, nsid, vnida, vnidb, vnidc, name);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- FS -----
|
||||
|
||||
// Unmount
|
||||
status_t
|
||||
Volume::Unmount()
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Sync
|
||||
status_t
|
||||
Volume::Sync()
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// ReadFSStat
|
||||
status_t
|
||||
Volume::ReadFSStat(fs_info* info)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// WriteFSStat
|
||||
status_t
|
||||
Volume::WriteFSStat(struct fs_info* info, int32 mask)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- vnodes -----
|
||||
|
||||
// ReadVNode
|
||||
status_t
|
||||
Volume::ReadVNode(vnode_id vnid, char reenter, Node** _node)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// WriteVNode
|
||||
status_t
|
||||
Volume::WriteVNode(Node* node, char reenter)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// RemoveVNode
|
||||
status_t
|
||||
Volume::RemoveVNode(Node* node, char reenter)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- nodes -----
|
||||
|
||||
// FSync
|
||||
status_t
|
||||
Volume::FSync(Node* node)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// ReadStat
|
||||
status_t
|
||||
Volume::ReadStat(Node* node, struct stat* st)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// WriteStat
|
||||
status_t
|
||||
Volume::WriteStat(Node* node, struct stat *st, uint32 mask)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Access
|
||||
status_t
|
||||
Volume::Access(Node* node, int mode)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- files -----
|
||||
|
||||
// Create
|
||||
status_t
|
||||
Volume::Create(Node* dir, const char* name, int openMode, int mode,
|
||||
vnode_id* vnid, void** cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Open
|
||||
status_t
|
||||
Volume::Open(Node* node, int openMode, void** cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Close
|
||||
status_t
|
||||
Volume::Close(Node* node, void* cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// FreeCookie
|
||||
status_t
|
||||
Volume::FreeCookie(Node* node, void* cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Read
|
||||
status_t
|
||||
Volume::Read(Node* node, void* cookie, off_t pos, void* _buffer,
|
||||
size_t bufferSize, size_t* _bytesRead)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Write
|
||||
status_t
|
||||
Volume::Write(Node* node, void* cookie, off_t pos, const void* _buffer,
|
||||
size_t bufferSize, size_t* bytesWritten)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// IOCtl
|
||||
status_t
|
||||
Volume::IOCtl(Node* node, void* cookie, int cmd, void* buffer,
|
||||
size_t bufferSize)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// SetFlags
|
||||
status_t
|
||||
Volume::SetFlags(Node* node, void* cookie, int flags)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- hard links / symlinks -----
|
||||
|
||||
// Link
|
||||
status_t
|
||||
Volume::Link(Node* dir, const char* name, Node* node)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Unlink
|
||||
status_t
|
||||
Volume::Unlink(Node* dir, const char* name)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Symlink
|
||||
status_t
|
||||
Volume::Symlink(Node* dir, const char* name, const char* target)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// ReadLink
|
||||
status_t
|
||||
Volume::ReadLink(Node* node, char* buffer, size_t bufferSize,
|
||||
size_t* bytesRead)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Rename
|
||||
status_t
|
||||
Volume::Rename(Node* oldDir, const char* oldName, Node* newDir,
|
||||
const char* newName)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- directories -----
|
||||
|
||||
// MkDir
|
||||
status_t
|
||||
Volume::MkDir(Node* dir, const char* name, int mode)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// RmDir
|
||||
status_t
|
||||
Volume::RmDir(Node* dir, const char* name)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// OpenDir
|
||||
status_t
|
||||
Volume::OpenDir(Node* node, void** _cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// CloseDir
|
||||
status_t
|
||||
Volume::CloseDir(Node* node, void* cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// FreeDirCookie
|
||||
status_t
|
||||
Volume::FreeDirCookie(Node* node, void* _cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// ReadDir
|
||||
status_t
|
||||
Volume::ReadDir(Node* node, void* _cookie, struct dirent* buffer,
|
||||
size_t bufferSize, int32 count, int32* countRead)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// RewindDir
|
||||
status_t
|
||||
Volume::RewindDir(Node* node, void* _cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Walk
|
||||
status_t
|
||||
Volume::Walk(Node* dir, const char* entryName, char** resolvedPath,
|
||||
vnode_id* vnid)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- attributes -----
|
||||
|
||||
// OpenAttrDir
|
||||
status_t
|
||||
Volume::OpenAttrDir(Node* node, void** _cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// CloseAttrDir
|
||||
status_t
|
||||
Volume::CloseAttrDir(Node* node, void* cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// FreeAttrDirCookie
|
||||
status_t
|
||||
Volume::FreeAttrDirCookie(Node* node, void* _cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// ReadAttrDir
|
||||
status_t
|
||||
Volume::ReadAttrDir(Node* node, void* _cookie, struct dirent* buffer,
|
||||
size_t bufferSize, int32 count, int32* countRead)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// RewindAttrDir
|
||||
status_t
|
||||
Volume::RewindAttrDir(Node* node, void* _cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// ReadAttr
|
||||
status_t
|
||||
Volume::ReadAttr(Node* node, const char* name, int type, off_t pos,
|
||||
void* _buffer, size_t bufferSize, size_t* _bytesRead)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// WriteAttr
|
||||
status_t
|
||||
Volume::WriteAttr(Node* node, const char* name, int type, off_t pos,
|
||||
const void* _buffer, size_t bufferSize, size_t* bytesWritten)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// RemoveAttr
|
||||
status_t
|
||||
Volume::RemoveAttr(Node* node, const char* name)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// RenameAttr
|
||||
status_t
|
||||
Volume::RenameAttr(Node* node, const char* oldName, const char* newName)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// StatAttr
|
||||
status_t
|
||||
Volume::StatAttr(Node* node, const char* name, struct attr_info* attrInfo)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- queries -----
|
||||
|
||||
// OpenQuery
|
||||
status_t
|
||||
Volume::OpenQuery(const char* queryString, uint32 flags, port_id port,
|
||||
int32 token, QueryIterator** iterator)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// FreeQueryIterator
|
||||
void
|
||||
Volume::FreeQueryIterator(QueryIterator* iterator)
|
||||
{
|
||||
}
|
||||
|
||||
// ReadQuery
|
||||
status_t
|
||||
Volume::ReadQuery(QueryIterator* iterator, struct dirent* buffer,
|
||||
size_t bufferSize, int32 count, int32* countRead)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
166
src/add-ons/kernel/file_systems/netfs/client/Volume.h
Normal file
166
src/add-ons/kernel/file_systems/netfs/client/Volume.h
Normal file
@ -0,0 +1,166 @@
|
||||
// Volume.h
|
||||
|
||||
#ifndef NET_FS_VOLUME_H
|
||||
#define NET_FS_VOLUME_H
|
||||
|
||||
#include <fsproto.h>
|
||||
|
||||
#include <HashString.h>
|
||||
|
||||
#include "FSObject.h"
|
||||
#include "Locker.h"
|
||||
|
||||
class Node;
|
||||
class QueryIterator;
|
||||
class VolumeEvent;
|
||||
class VolumeManager;
|
||||
|
||||
class Volume : public FSObject {
|
||||
public:
|
||||
Volume(VolumeManager* volumeManager);
|
||||
~Volume();
|
||||
|
||||
VolumeManager* GetVolumeManager() const;
|
||||
|
||||
void SetParentVolume(Volume* parent);
|
||||
Volume* GetParentVolume() const;
|
||||
// TODO: Add the parent node ID and maybe get rid of parent volume.
|
||||
|
||||
void PutVolume();
|
||||
|
||||
status_t Init(const char* name);
|
||||
void Uninit();
|
||||
|
||||
const char* GetName() const;
|
||||
|
||||
vnode_id GetRootID() const;
|
||||
virtual Node* GetRootNode() const = 0;
|
||||
|
||||
void SetUnmounting(bool unmounting);
|
||||
bool IsUnmounting() const;
|
||||
|
||||
virtual void PrepareToUnmount();
|
||||
|
||||
virtual void RemoveChildVolume(Volume* volume) = 0;
|
||||
|
||||
virtual void HandleEvent(VolumeEvent* event);
|
||||
|
||||
// client methods
|
||||
status_t GetVNode(vnode_id vnid, Node** node);
|
||||
status_t PutVNode(vnode_id vnid);
|
||||
status_t NewVNode(vnode_id vnid, Node* node);
|
||||
status_t RemoveVNode(vnode_id vnid);
|
||||
status_t UnremoveVNode(vnode_id vnid);
|
||||
int IsVNodeRemoved(vnode_id vnid);
|
||||
|
||||
int SendNotification(port_id port, int32 token,
|
||||
uint32 what, int32 op, nspace_id nsida,
|
||||
nspace_id nsidb, vnode_id vnida,
|
||||
vnode_id vnidb, vnode_id vnidc,
|
||||
const char *name);
|
||||
int NotifyListener(int32 opcode, nspace_id nsid,
|
||||
vnode_id vnida, vnode_id vnidb,
|
||||
vnode_id vnidc, const char *name);
|
||||
|
||||
// FS
|
||||
virtual status_t Unmount();
|
||||
virtual status_t Sync();
|
||||
virtual status_t ReadFSStat(fs_info* info);
|
||||
virtual status_t WriteFSStat(struct fs_info* info, int32 mask);
|
||||
|
||||
// vnodes
|
||||
virtual status_t ReadVNode(vnode_id vnid, char reenter,
|
||||
Node** node);
|
||||
virtual status_t WriteVNode(Node* node, char reenter);
|
||||
virtual status_t RemoveVNode(Node* node, char reenter);
|
||||
|
||||
// nodes
|
||||
virtual status_t FSync(Node* node);
|
||||
virtual status_t ReadStat(Node* node, struct stat* st);
|
||||
virtual status_t WriteStat(Node* node, struct stat *st,
|
||||
uint32 mask);
|
||||
virtual status_t Access(Node* node, int mode);
|
||||
|
||||
// files
|
||||
virtual status_t Create(Node* dir, const char* name,
|
||||
int openMode, int mode, vnode_id* vnid,
|
||||
void** cookie);
|
||||
virtual status_t Open(Node* node, int openMode,
|
||||
void** cookie);
|
||||
virtual status_t Close(Node* node, void* cookie);
|
||||
virtual status_t FreeCookie(Node* node, void* cookie);
|
||||
virtual status_t Read(Node* node, void* cookie, off_t pos,
|
||||
void* buffer, size_t bufferSize,
|
||||
size_t* bytesRead);
|
||||
virtual status_t Write(Node* node, void* cookie, off_t pos,
|
||||
const void* buffer, size_t bufferSize,
|
||||
size_t* bytesWritten);
|
||||
virtual status_t IOCtl(Node* node, void* cookie, int cmd,
|
||||
void* buffer, size_t bufferSize);
|
||||
virtual status_t SetFlags(Node* node, void* cookie,
|
||||
int flags);
|
||||
|
||||
// hard links / symlinks
|
||||
virtual status_t Link(Node* dir, const char* name,
|
||||
Node* node);
|
||||
virtual status_t Unlink(Node* dir, const char* name);
|
||||
virtual status_t Symlink(Node* dir, const char* name,
|
||||
const char* target);
|
||||
virtual status_t ReadLink(Node* node, char* buffer,
|
||||
size_t bufferSize, size_t* bytesRead);
|
||||
virtual status_t Rename(Node* oldDir, const char* oldName,
|
||||
Node* newDir, const char* newName);
|
||||
|
||||
// directories
|
||||
virtual status_t MkDir(Node* dir, const char* name,
|
||||
int mode);
|
||||
virtual status_t RmDir(Node* dir, const char* name);
|
||||
virtual status_t OpenDir(Node* node, void** cookie);
|
||||
virtual status_t CloseDir(Node* node, void* cookie);
|
||||
virtual status_t FreeDirCookie(Node* node, void* cookie);
|
||||
virtual status_t ReadDir(Node* node, void* cookie,
|
||||
struct dirent* buffer, size_t bufferSize,
|
||||
int32 count, int32* countRead);
|
||||
virtual status_t RewindDir(Node* node, void* cookie);
|
||||
virtual status_t Walk(Node* dir, const char* entryName,
|
||||
char** resolvedPath, vnode_id* vnid);
|
||||
|
||||
// attributes
|
||||
virtual status_t OpenAttrDir(Node* node, void** cookie);
|
||||
virtual status_t CloseAttrDir(Node* node, void* cookie);
|
||||
virtual status_t FreeAttrDirCookie(Node* node,
|
||||
void* cookie);
|
||||
virtual status_t ReadAttrDir(Node* node, void* cookie,
|
||||
struct dirent* buffer, size_t bufferSize,
|
||||
int32 count, int32* countRead);
|
||||
virtual status_t RewindAttrDir(Node* node, void* cookie);
|
||||
virtual status_t ReadAttr(Node* node, const char* name,
|
||||
int type, off_t pos, void* buffer,
|
||||
size_t bufferSize, size_t* bytesRead);
|
||||
virtual status_t WriteAttr(Node* node, const char* name,
|
||||
int type, off_t pos, const void* buffer,
|
||||
size_t bufferSize, size_t* bytesWritten);
|
||||
virtual status_t RemoveAttr(Node* node, const char* name);
|
||||
virtual status_t RenameAttr(Node* node,
|
||||
const char* oldName, const char* newName);
|
||||
virtual status_t StatAttr(Node* node, const char* name,
|
||||
struct attr_info* attrInfo);
|
||||
|
||||
// queries
|
||||
virtual status_t OpenQuery(const char* queryString,
|
||||
uint32 flags, port_id port, int32 token,
|
||||
QueryIterator** iterator);
|
||||
virtual void FreeQueryIterator(QueryIterator* iterator);
|
||||
virtual status_t ReadQuery(QueryIterator* iterator,
|
||||
struct dirent* buffer, size_t bufferSize,
|
||||
int32 count, int32* countRead);
|
||||
|
||||
protected:
|
||||
Locker fLock;
|
||||
VolumeManager* fVolumeManager;
|
||||
Volume* fParentVolume;
|
||||
HashString fName;
|
||||
bool fUnmounting;
|
||||
};
|
||||
|
||||
#endif // NET_FS_VOLUME_H
|
53
src/add-ons/kernel/file_systems/netfs/client/VolumeEvent.cpp
Normal file
53
src/add-ons/kernel/file_systems/netfs/client/VolumeEvent.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
// VolumeEvent.cpp
|
||||
|
||||
#include "VolumeEvent.h"
|
||||
|
||||
// constructor
|
||||
VolumeEvent::VolumeEvent(uint32 type, vnode_id target)
|
||||
:
|
||||
BReferenceable(true),
|
||||
fType(type),
|
||||
fTarget(target)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
VolumeEvent::~VolumeEvent()
|
||||
{
|
||||
}
|
||||
|
||||
// GetType
|
||||
uint32
|
||||
VolumeEvent::GetType() const
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
|
||||
// SetTarget
|
||||
void
|
||||
VolumeEvent::SetTarget(vnode_id target)
|
||||
{
|
||||
fTarget = target;
|
||||
}
|
||||
|
||||
// GetTarget
|
||||
vnode_id
|
||||
VolumeEvent::GetTarget() const
|
||||
{
|
||||
return fTarget;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
ConnectionBrokenEvent::ConnectionBrokenEvent(vnode_id target)
|
||||
: VolumeEvent(CONNECTION_BROKEN_EVENT, target)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ConnectionBrokenEvent::~ConnectionBrokenEvent()
|
||||
{
|
||||
}
|
||||
|
43
src/add-ons/kernel/file_systems/netfs/client/VolumeEvent.h
Normal file
43
src/add-ons/kernel/file_systems/netfs/client/VolumeEvent.h
Normal file
@ -0,0 +1,43 @@
|
||||
// VolumeEvent.h
|
||||
|
||||
#ifndef NETFS_VOLUME_EVENT_H
|
||||
#define NETFS_VOLUME_EVENT_H
|
||||
|
||||
#include <fsproto.h>
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
|
||||
// event types
|
||||
enum {
|
||||
CONNECTION_BROKEN_EVENT,
|
||||
};
|
||||
|
||||
// VolumeEvent
|
||||
class VolumeEvent : public BReferenceable,
|
||||
public DoublyLinkedListLinkImpl<VolumeEvent> {
|
||||
public:
|
||||
VolumeEvent(uint32 type, vnode_id target = -1);
|
||||
virtual ~VolumeEvent();
|
||||
|
||||
uint32 GetType() const;
|
||||
|
||||
void SetTarget(vnode_id target);
|
||||
vnode_id GetTarget() const;
|
||||
// a node ID identifying the target volume (usually the ID
|
||||
// of the root node)
|
||||
|
||||
private:
|
||||
uint32 fType;
|
||||
vnode_id fTarget;
|
||||
};
|
||||
|
||||
// ConnectionBrokenEvent
|
||||
class ConnectionBrokenEvent : public VolumeEvent {
|
||||
public:
|
||||
ConnectionBrokenEvent(vnode_id target = -1);
|
||||
virtual ~ConnectionBrokenEvent();
|
||||
};
|
||||
|
||||
#endif // NETFS_VOLUME_EVENT_H
|
407
src/add-ons/kernel/file_systems/netfs/client/VolumeManager.cpp
Normal file
407
src/add-ons/kernel/file_systems/netfs/client/VolumeManager.cpp
Normal file
@ -0,0 +1,407 @@
|
||||
// VolumeManager.cpp
|
||||
|
||||
#include <HashMap.h>
|
||||
#include <HashSet.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include "DebugSupport.h"
|
||||
#include "QueryManager.h"
|
||||
#include "RootVolume.h"
|
||||
#include "VolumeEvent.h"
|
||||
#include "VolumeManager.h"
|
||||
|
||||
// VolumeSet
|
||||
struct VolumeManager::VolumeSet : HashSet<HashKey32<Volume*> > {
|
||||
};
|
||||
|
||||
// NodeIDVolumeMap
|
||||
struct VolumeManager::NodeIDVolumeMap : HashMap<HashKey64<vnode_id>, Volume*> {
|
||||
};
|
||||
|
||||
// VolumeEventQueue
|
||||
class VolumeManager::VolumeEventQueue {
|
||||
public:
|
||||
VolumeEventQueue()
|
||||
: fLock("volume event queue"),
|
||||
fCounterSem(-1)
|
||||
{
|
||||
fCounterSem = create_sem(0, "volume event count");
|
||||
#if !USER
|
||||
if (fCounterSem >= 0)
|
||||
set_sem_owner(fCounterSem, B_SYSTEM_TEAM);
|
||||
#endif
|
||||
}
|
||||
|
||||
~VolumeEventQueue()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
status_t InitCheck() const
|
||||
{
|
||||
if (fCounterSem < 0)
|
||||
return fCounterSem;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
AutoLocker<Locker> _(fLock);
|
||||
if (fCounterSem >= 0) {
|
||||
delete_sem(fCounterSem);
|
||||
fCounterSem = -1;
|
||||
}
|
||||
|
||||
while (VolumeEvent* event = fEvents.First()) {
|
||||
fEvents.Remove(event);
|
||||
event->RemoveReference();
|
||||
}
|
||||
}
|
||||
|
||||
void Push(VolumeEvent* event)
|
||||
{
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
AutoLocker<Locker> _(fLock);
|
||||
if (fCounterSem < 0)
|
||||
return;
|
||||
fEvents.Insert(event);
|
||||
event->AddReference();
|
||||
release_sem(fCounterSem);
|
||||
}
|
||||
|
||||
VolumeEvent* Pop()
|
||||
{
|
||||
status_t error;
|
||||
do {
|
||||
error = acquire_sem(fCounterSem);
|
||||
} while (error == B_INTERRUPTED);
|
||||
if (error != B_OK)
|
||||
return NULL;
|
||||
|
||||
AutoLocker<Locker> _(fLock);
|
||||
if (VolumeEvent* event = fEvents.First()) {
|
||||
fEvents.Remove(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
Locker fLock;
|
||||
sem_id fCounterSem;
|
||||
DoublyLinkedList<VolumeEvent> fEvents;
|
||||
};
|
||||
|
||||
|
||||
// constructor
|
||||
VolumeManager::VolumeManager(nspace_id id, uint32 flags)
|
||||
: Locker("volume manager"),
|
||||
fID(id),
|
||||
fMountFlags(flags),
|
||||
fMountUID(0),
|
||||
fMountGID(0),
|
||||
fRootID(-1),
|
||||
fNextNodeID(2),
|
||||
fQueryManager(NULL),
|
||||
fVolumes(NULL),
|
||||
fNodeIDs2Volumes(NULL),
|
||||
fVolumeEvents(NULL),
|
||||
fEventDeliverer(-1)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
VolumeManager::~VolumeManager()
|
||||
{
|
||||
if (fVolumeEvents)
|
||||
fVolumeEvents->Close();
|
||||
if (fEventDeliverer >= 0) {
|
||||
int32 result;
|
||||
wait_for_thread(fEventDeliverer, &result);
|
||||
}
|
||||
delete fVolumeEvents;
|
||||
delete fVolumes;
|
||||
delete fNodeIDs2Volumes;
|
||||
delete fQueryManager;
|
||||
}
|
||||
|
||||
// MountRootVolume
|
||||
status_t
|
||||
VolumeManager::MountRootVolume(const char* device,
|
||||
const char* parameters, int32 len, Volume** volume)
|
||||
{
|
||||
// Store the uid/gid of the mounting user -- when running in userland
|
||||
// this is always the owner of the UserlandFS server, but we can't help
|
||||
// that.
|
||||
fMountUID = geteuid();
|
||||
fMountGID = getegid();
|
||||
|
||||
// create the query manager
|
||||
fQueryManager = new(std::nothrow) QueryManager(this);
|
||||
if (!fQueryManager)
|
||||
return B_NO_MEMORY;
|
||||
status_t error = fQueryManager->Init();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create volumes set
|
||||
fVolumes = new(std::nothrow) VolumeSet;
|
||||
if (!fVolumes)
|
||||
return B_NO_MEMORY;
|
||||
error = fVolumes->InitCheck();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create node ID to volumes map
|
||||
fNodeIDs2Volumes = new(std::nothrow) NodeIDVolumeMap;
|
||||
if (!fNodeIDs2Volumes)
|
||||
return B_NO_MEMORY;
|
||||
error = fNodeIDs2Volumes->InitCheck();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create the volume event queue
|
||||
fVolumeEvents = new VolumeEventQueue;
|
||||
if (!fVolumeEvents)
|
||||
return B_NO_MEMORY;
|
||||
error = fVolumeEvents->InitCheck();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// spawn the event deliverer
|
||||
#if USER
|
||||
fEventDeliverer = spawn_thread(&_EventDelivererEntry,
|
||||
"volume event deliverer", B_NORMAL_PRIORITY, this);
|
||||
#else
|
||||
fEventDeliverer = spawn_kernel_thread(&_EventDelivererEntry,
|
||||
"volume event deliverer", B_NORMAL_PRIORITY, this);
|
||||
#endif
|
||||
if (fEventDeliverer < 0)
|
||||
return fEventDeliverer;
|
||||
|
||||
// create the root volume
|
||||
RootVolume* rootVolume = new(std::nothrow) RootVolume(this);
|
||||
if (!rootVolume)
|
||||
return B_NO_MEMORY;
|
||||
error = rootVolume->Init();
|
||||
if (error != B_OK) {
|
||||
delete rootVolume;
|
||||
return error;
|
||||
}
|
||||
fRootID = rootVolume->GetRootID();
|
||||
|
||||
// add the root volume
|
||||
error = AddVolume(rootVolume);
|
||||
if (error != B_OK) {
|
||||
delete rootVolume;
|
||||
return error;
|
||||
}
|
||||
|
||||
// mount the root volume
|
||||
error = rootVolume->Mount(device, fMountFlags, (const char*)parameters,
|
||||
len);
|
||||
if (error != B_OK) {
|
||||
rootVolume->SetUnmounting(true);
|
||||
PutVolume(rootVolume);
|
||||
return error;
|
||||
}
|
||||
rootVolume->AddReference();
|
||||
*volume = rootVolume;
|
||||
|
||||
// run the event deliverer
|
||||
resume_thread(fEventDeliverer);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// UnmountRootVolume
|
||||
void
|
||||
VolumeManager::UnmountRootVolume()
|
||||
{
|
||||
if (Volume* rootVolume = GetRootVolume()) {
|
||||
rootVolume->SetUnmounting(true);
|
||||
PutVolume(rootVolume);
|
||||
} else {
|
||||
ERROR(("VolumeManager::UnmountRootVolume(): ERROR: Couldn't get "
|
||||
"root volume!\n"));
|
||||
}
|
||||
}
|
||||
|
||||
// GetQueryManager
|
||||
QueryManager*
|
||||
VolumeManager::GetQueryManager() const
|
||||
{
|
||||
return fQueryManager;
|
||||
}
|
||||
|
||||
// GetRootVolume
|
||||
Volume*
|
||||
VolumeManager::GetRootVolume()
|
||||
{
|
||||
return GetVolume(fRootID);
|
||||
}
|
||||
|
||||
// AddVolume
|
||||
//
|
||||
// The caller must have a reference to the volume and retains it.
|
||||
status_t
|
||||
VolumeManager::AddVolume(Volume* volume)
|
||||
{
|
||||
if (!volume)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// check, if it already exists
|
||||
AutoLocker<Locker> _(this);
|
||||
if (fVolumes->Contains(volume))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// add the volume
|
||||
return fVolumes->Add(volume);
|
||||
}
|
||||
|
||||
// GetVolume
|
||||
Volume*
|
||||
VolumeManager::GetVolume(vnode_id nodeID)
|
||||
{
|
||||
AutoLocker<Locker> _(this);
|
||||
Volume* volume = fNodeIDs2Volumes->Get(nodeID);
|
||||
if (volume && GetVolume(volume))
|
||||
return volume;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// GetVolume
|
||||
Volume*
|
||||
VolumeManager::GetVolume(Volume* volume)
|
||||
{
|
||||
if (!volume)
|
||||
return NULL;
|
||||
|
||||
AutoLocker<Locker> _(this);
|
||||
if (fVolumes->Contains(volume)) {
|
||||
// TODO: Any restrictions regarding volumes about to be removed?
|
||||
volume->AddReference();
|
||||
return volume;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// PutVolume
|
||||
//
|
||||
// The VolumeManager must not be locked, when this method is invoked.
|
||||
void
|
||||
VolumeManager::PutVolume(Volume* volume)
|
||||
{
|
||||
if (!volume)
|
||||
return;
|
||||
|
||||
// If the volume is marked unmounting and is not yet marked removed, we
|
||||
// initiate the removal process.
|
||||
{
|
||||
AutoLocker<Locker> locker(this);
|
||||
//PRINT(("VolumeManager::PutVolume(%p): reference count before: %ld\n",
|
||||
//volume, volume->CountReferences()));
|
||||
if (volume->IsUnmounting() && !volume->IsRemoved()) {
|
||||
//PRINT(("VolumeManager::PutVolume(%p): Volume connection broken, marking "
|
||||
//"removed and removing all nodes.\n", volume));
|
||||
// mark removed
|
||||
volume->MarkRemoved();
|
||||
|
||||
// get parent volume
|
||||
Volume* parentVolume = volume->GetParentVolume();
|
||||
if (parentVolume && !GetVolume(parentVolume))
|
||||
parentVolume = NULL;
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
// prepare to unmount
|
||||
volume->PrepareToUnmount();
|
||||
|
||||
// remove from parent volume
|
||||
if (parentVolume) {
|
||||
parentVolume->RemoveChildVolume(volume);
|
||||
PutVolume(parentVolume);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the volume is marked removed and it's reference count drops to 0,
|
||||
// we unmount and delete it.
|
||||
{
|
||||
AutoLocker<Locker> locker(this);
|
||||
if (volume->RemoveReference() && volume->IsRemoved()) {
|
||||
PRINT(("VolumeManager::PutVolume(%p): Removed volume unreferenced. "
|
||||
"Unmounting...\n", volume));
|
||||
// remove from volume set -- now noone can get a reference to it
|
||||
// anymore
|
||||
fVolumes->Remove(volume);
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
// unmount and delete the volume
|
||||
// TODO: At some point all the volume's node IDs have to be removed from
|
||||
// fNodeIDs2Volumes. For the time being we expect the volume to do that itself
|
||||
// in Unmount().
|
||||
volume->Unmount();
|
||||
delete volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewNodeID
|
||||
vnode_id
|
||||
VolumeManager::NewNodeID(Volume* volume)
|
||||
{
|
||||
if (!volume)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
AutoLocker<Locker> _(this);
|
||||
vnode_id nodeID = fNextNodeID;
|
||||
status_t error = fNodeIDs2Volumes->Put(nodeID, volume);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
return fNextNodeID++;
|
||||
}
|
||||
|
||||
// RemoveNodeID
|
||||
void
|
||||
VolumeManager::RemoveNodeID(vnode_id nodeID)
|
||||
{
|
||||
AutoLocker<Locker> _(this);
|
||||
fNodeIDs2Volumes->Remove(nodeID);
|
||||
}
|
||||
|
||||
// SendVolumeEvent
|
||||
void
|
||||
VolumeManager::SendVolumeEvent(VolumeEvent* event)
|
||||
{
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
fVolumeEvents->Push(event);
|
||||
}
|
||||
|
||||
// _EventDelivererEntry
|
||||
int32
|
||||
VolumeManager::_EventDelivererEntry(void* data)
|
||||
{
|
||||
return ((VolumeManager*)data)->_EventDeliverer();
|
||||
}
|
||||
|
||||
// _EventDeliverer
|
||||
int32
|
||||
VolumeManager::_EventDeliverer()
|
||||
{
|
||||
while (VolumeEvent* event = fVolumeEvents->Pop()) {
|
||||
if (Volume* volume = GetVolume(event->GetTarget())) {
|
||||
volume->HandleEvent(event);
|
||||
PutVolume(volume);
|
||||
}
|
||||
event->RemoveReference();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
100
src/add-ons/kernel/file_systems/netfs/client/VolumeManager.h
Normal file
100
src/add-ons/kernel/file_systems/netfs/client/VolumeManager.h
Normal file
@ -0,0 +1,100 @@
|
||||
// VolumeManager.h
|
||||
|
||||
#ifndef NET_FS_VOLUME_MANAGER_H
|
||||
#define NET_FS_VOLUME_MANAGER_H
|
||||
|
||||
#include "Locker.h"
|
||||
#include "Volume.h"
|
||||
|
||||
class QueryManager;
|
||||
class RootVolume;
|
||||
class Volume;
|
||||
class VolumeEvent;
|
||||
|
||||
// VolumeManager
|
||||
class VolumeManager : private Locker {
|
||||
public:
|
||||
VolumeManager(nspace_id id, uint32 flags);
|
||||
~VolumeManager();
|
||||
|
||||
nspace_id GetID() const { return fID; }
|
||||
uint32 GetMountFlags() const { return fMountFlags; }
|
||||
uid_t GetMountUID() const { return fMountUID; }
|
||||
uid_t GetMountGID() const { return fMountGID; }
|
||||
|
||||
status_t MountRootVolume(const char* device,
|
||||
const char* parameters, int32 len,
|
||||
Volume** volume);
|
||||
void UnmountRootVolume();
|
||||
|
||||
QueryManager* GetQueryManager() const;
|
||||
|
||||
Volume* GetRootVolume();
|
||||
status_t AddVolume(Volume* volume);
|
||||
Volume* GetVolume(vnode_id nodeID);
|
||||
private:
|
||||
Volume* GetVolume(Volume* volume);
|
||||
// TODO: This is actually a bit dangerous, since the volume
|
||||
// might be delete and another one reallocated at the same
|
||||
// location. (Use the node ID of its root node instead?!)
|
||||
public:
|
||||
void PutVolume(Volume* volume);
|
||||
|
||||
vnode_id NewNodeID(Volume* volume);
|
||||
void RemoveNodeID(vnode_id nodeID);
|
||||
|
||||
void SendVolumeEvent(VolumeEvent* event);
|
||||
|
||||
private:
|
||||
struct VolumeSet;
|
||||
struct NodeIDVolumeMap;
|
||||
class VolumeEventQueue;
|
||||
|
||||
static int32 _EventDelivererEntry(void* data);
|
||||
int32 _EventDeliverer();
|
||||
|
||||
private:
|
||||
nspace_id fID;
|
||||
uint32 fMountFlags;
|
||||
uid_t fMountUID;
|
||||
gid_t fMountGID;
|
||||
vnode_id fRootID;
|
||||
volatile vnode_id fNextNodeID;
|
||||
QueryManager* fQueryManager;
|
||||
VolumeSet* fVolumes;
|
||||
NodeIDVolumeMap* fNodeIDs2Volumes;
|
||||
VolumeEventQueue* fVolumeEvents;
|
||||
thread_id fEventDeliverer;
|
||||
};
|
||||
|
||||
// VolumePutter
|
||||
class VolumePutter {
|
||||
public:
|
||||
VolumePutter(Volume* volume)
|
||||
: fVolume(volume)
|
||||
{
|
||||
}
|
||||
|
||||
~VolumePutter()
|
||||
{
|
||||
Put();
|
||||
}
|
||||
|
||||
void Put()
|
||||
{
|
||||
if (fVolume) {
|
||||
fVolume->PutVolume();
|
||||
fVolume = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Detach()
|
||||
{
|
||||
fVolume = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
Volume* fVolume;
|
||||
};
|
||||
|
||||
#endif // NET_FS_VOLUME_MANAGER_H
|
48
src/add-ons/kernel/file_systems/netfs/client/VolumeSupport.h
Normal file
48
src/add-ons/kernel/file_systems/netfs/client/VolumeSupport.h
Normal file
@ -0,0 +1,48 @@
|
||||
// VolumeSupport.h
|
||||
|
||||
#ifndef NET_FS_VOLUME_SUPPORT_H
|
||||
#define NET_FS_VOLUME_SUPPORT_H
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include "DebugSupport.h"
|
||||
|
||||
// set_dirent_name
|
||||
static inline
|
||||
status_t
|
||||
set_dirent_name(struct dirent* buffer, size_t bufferSize, const char* name,
|
||||
int32 nameLen)
|
||||
{
|
||||
size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
|
||||
if (length <= bufferSize) {
|
||||
memcpy(buffer->d_name, name, nameLen);
|
||||
buffer->d_name[nameLen] = '\0';
|
||||
buffer->d_reclen = length;
|
||||
return B_OK;
|
||||
} else {
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
// next_dirent
|
||||
static inline
|
||||
bool
|
||||
next_dirent(struct dirent*& buffer, size_t& bufferSize)
|
||||
{
|
||||
// align
|
||||
char* nextBuffer = (char*)buffer + buffer->d_reclen;
|
||||
nextBuffer = (char*)(((uint32)nextBuffer + 3) & ~0x3);
|
||||
|
||||
// check, if the buffer is at least large enough to align the current entry
|
||||
int32 len = nextBuffer - (char*)buffer;
|
||||
if (len > (int32)bufferSize)
|
||||
return false;
|
||||
|
||||
buffer->d_reclen = len;
|
||||
buffer = (dirent*)nextBuffer;
|
||||
bufferSize -= len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // NET_FS_VOLUME_SUPPORT_H
|
926
src/add-ons/kernel/file_systems/netfs/client/netfs.cpp
Normal file
926
src/add-ons/kernel/file_systems/netfs/client/netfs.cpp
Normal file
@ -0,0 +1,926 @@
|
||||
// netfs.cpp
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <fsproto.h>
|
||||
|
||||
#include "DebugSupport.h"
|
||||
#include "Node.h"
|
||||
#include "ObjectTracker.h"
|
||||
#include "QueryManager.h"
|
||||
#include "RootVolume.h"
|
||||
#include "VolumeManager.h"
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- prototypes -----
|
||||
|
||||
extern "C" {
|
||||
|
||||
// fs
|
||||
static int netfs_mount(nspace_id nsid, const char *device, ulong flags,
|
||||
void *parameters, size_t len, void **data, vnode_id *rootID);
|
||||
static int netfs_unmount(void *ns);
|
||||
static int netfs_sync(void *ns);
|
||||
static int netfs_read_fs_stat(void *ns, struct fs_info *info);
|
||||
static int netfs_write_fs_stat(void *ns, struct fs_info *info, long mask);
|
||||
|
||||
// vnodes
|
||||
static int netfs_read_vnode(void *ns, vnode_id vnid, char reenter,
|
||||
void **node);
|
||||
static int netfs_write_vnode(void *ns, void *node, char reenter);
|
||||
static int netfs_remove_vnode(void *ns, void *node, char reenter);
|
||||
|
||||
// nodes
|
||||
static int netfs_fsync(void *ns, void *node);
|
||||
static int netfs_read_stat(void *ns, void *node, struct stat *st);
|
||||
static int netfs_write_stat(void *ns, void *node, struct stat *st,
|
||||
long mask);
|
||||
static int netfs_access(void *ns, void *node, int mode);
|
||||
|
||||
// files
|
||||
static int netfs_create(void *ns, void *dir, const char *name,
|
||||
int openMode, int mode, vnode_id *vnid, void **cookie);
|
||||
static int netfs_open(void *ns, void *node, int openMode, void **cookie);
|
||||
static int netfs_close(void *ns, void *node, void *cookie);
|
||||
static int netfs_free_cookie(void *ns, void *node, void *cookie);
|
||||
static int netfs_read(void *ns, void *node, void *cookie, off_t pos,
|
||||
void *buffer, size_t *bufferSize);
|
||||
static int netfs_write(void *ns, void *node, void *cookie, off_t pos,
|
||||
const void *buffer, size_t *bufferSize);
|
||||
static int netfs_ioctl(void *ns, void *node, void *cookie, int cmd,
|
||||
void *buffer, size_t bufferSize);
|
||||
static int netfs_setflags(void *ns, void *node, void *cookie, int flags);
|
||||
|
||||
// hard links / symlinks
|
||||
static int netfs_link(void *ns, void *dir, const char *name, void *node);
|
||||
static int netfs_unlink(void *ns, void *dir, const char *name);
|
||||
static int netfs_symlink(void *ns, void *dir, const char *name,
|
||||
const char *path);
|
||||
static int netfs_read_link(void *ns, void *node, char *buffer,
|
||||
size_t *bufferSize);
|
||||
static int netfs_rename(void *ns, void *oldDir, const char *oldName,
|
||||
void *newDir, const char *newName);
|
||||
|
||||
// directories
|
||||
static int netfs_mkdir(void *ns, void *dir, const char *name, int mode);
|
||||
static int netfs_rmdir(void *ns, void *dir, const char *name);
|
||||
static int netfs_open_dir(void *ns, void *node, void **cookie);
|
||||
static int netfs_close_dir(void *ns, void *node, void *cookie);
|
||||
static int netfs_free_dir_cookie(void *ns, void *node, void *cookie);
|
||||
static int netfs_read_dir(void *ns, void *node, void *cookie,
|
||||
long *count, struct dirent *buffer, size_t bufferSize);
|
||||
static int netfs_rewind_dir(void *ns, void *node, void *cookie);
|
||||
static int netfs_walk(void *ns, void *dir, const char *entryName,
|
||||
char **resolvedPath, vnode_id *vnid);
|
||||
|
||||
// attributes
|
||||
static int netfs_open_attrdir(void *ns, void *node, void **cookie);
|
||||
static int netfs_close_attrdir(void *ns, void *node, void *cookie);
|
||||
static int netfs_free_attrdir_cookie(void *ns, void *node, void *cookie);
|
||||
static int netfs_read_attrdir(void *ns, void *node, void *cookie,
|
||||
long *count, struct dirent *buffer, size_t bufferSize);
|
||||
static int netfs_read_attr(void *ns, void *node, const char *name,
|
||||
int type, void *buffer, size_t *bufferSize, off_t pos);
|
||||
static int netfs_rewind_attrdir(void *ns, void *node, void *cookie);
|
||||
static int netfs_write_attr(void *ns, void *node, const char *name,
|
||||
int type, const void *buffer, size_t *bufferSize, off_t pos);
|
||||
static int netfs_remove_attr(void *ns, void *node, const char *name);
|
||||
static int netfs_rename_attr(void *ns, void *node, const char *oldName,
|
||||
const char *newName);
|
||||
static int netfs_stat_attr(void *ns, void *node, const char *name,
|
||||
struct attr_info *attrInfo);
|
||||
|
||||
// queries
|
||||
static int netfs_open_query(void *ns, const char *queryString, ulong flags,
|
||||
port_id port, long token, void **cookie);
|
||||
static int netfs_close_query(void *ns, void *cookie);
|
||||
static int netfs_free_query_cookie(void *ns, void *node, void *cookie);
|
||||
static int netfs_read_query(void *ns, void *cookie, long *count,
|
||||
struct dirent *buffer, size_t bufferSize);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
/* vnode_ops struct. Fill this in to tell the kernel how to call
|
||||
functions in your driver.
|
||||
*/
|
||||
vnode_ops fs_entry = {
|
||||
&netfs_read_vnode, // read_vnode
|
||||
&netfs_write_vnode, // write_vnode
|
||||
&netfs_remove_vnode, // remove_vnode
|
||||
NULL, // secure_vnode (not needed)
|
||||
&netfs_walk, // walk
|
||||
&netfs_access, // access
|
||||
&netfs_create, // create
|
||||
&netfs_mkdir, // mkdir
|
||||
&netfs_symlink, // symlink
|
||||
&netfs_link, // link
|
||||
&netfs_rename, // rename
|
||||
&netfs_unlink, // unlink
|
||||
&netfs_rmdir, // rmdir
|
||||
&netfs_read_link, // readlink
|
||||
&netfs_open_dir, // opendir
|
||||
&netfs_close_dir, // closedir
|
||||
&netfs_free_dir_cookie, // free_dircookie
|
||||
&netfs_rewind_dir, // rewinddir
|
||||
&netfs_read_dir, // readdir
|
||||
&netfs_open, // open file
|
||||
&netfs_close, // close file
|
||||
&netfs_free_cookie, // free cookie
|
||||
&netfs_read, // read file
|
||||
&netfs_write, // write file
|
||||
NULL, // readv
|
||||
NULL, // writev
|
||||
&netfs_ioctl, // ioctl
|
||||
NULL, // setflags file
|
||||
&netfs_read_stat, // read stat
|
||||
&netfs_write_stat, // write stat
|
||||
NULL, // fsync
|
||||
NULL, // initialize
|
||||
&netfs_mount, // mount
|
||||
&netfs_unmount, // unmount
|
||||
NULL, // sync
|
||||
&netfs_read_fs_stat, // read fs stat
|
||||
NULL, // write fs stat
|
||||
NULL, // select
|
||||
NULL, // deselect
|
||||
|
||||
NULL, // open index dir
|
||||
NULL, // close index dir
|
||||
NULL, // free index dir cookie
|
||||
NULL, // rewind index dir
|
||||
NULL, // read index dir
|
||||
NULL, // create index
|
||||
NULL, // remove index
|
||||
NULL, // rename index
|
||||
NULL, // stat index
|
||||
|
||||
&netfs_open_attrdir, // open attr dir
|
||||
&netfs_close_attrdir, // close attr dir
|
||||
&netfs_free_attrdir_cookie, // free attr dir cookie
|
||||
&netfs_rewind_attrdir, // rewind attr dir
|
||||
&netfs_read_attrdir, // read attr dir
|
||||
&netfs_write_attr, // write attr
|
||||
&netfs_read_attr, // read attr
|
||||
&netfs_remove_attr, // remove attr
|
||||
&netfs_rename_attr, // rename attr
|
||||
&netfs_stat_attr, // stat attr
|
||||
|
||||
&netfs_open_query, // open query
|
||||
&netfs_close_query, // close query
|
||||
&netfs_free_query_cookie, // free query cookie
|
||||
&netfs_read_query, // read query
|
||||
};
|
||||
|
||||
int32 api_version = B_CUR_FS_API_VERSION;
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- fs -----
|
||||
|
||||
// netfs_mount
|
||||
static
|
||||
int
|
||||
netfs_mount(nspace_id nsid, const char *device, ulong flags,
|
||||
void *parameters, size_t len, void **data, vnode_id *rootID)
|
||||
{
|
||||
status_t error = B_OK;
|
||||
init_debugging();
|
||||
|
||||
#ifdef DEBUG_OBJECT_TRACKING
|
||||
ObjectTracker::InitDefault();
|
||||
#endif
|
||||
|
||||
// create and init the volume manager
|
||||
VolumeManager* volumeManager = new(std::nothrow) VolumeManager(nsid, flags);
|
||||
Volume* rootVolume = NULL;
|
||||
if (volumeManager) {
|
||||
error = volumeManager->MountRootVolume(device,
|
||||
(const char*)parameters, len, &rootVolume);
|
||||
if (error != B_OK) {
|
||||
delete volumeManager;
|
||||
volumeManager = NULL;
|
||||
}
|
||||
} else
|
||||
error = B_NO_MEMORY;
|
||||
VolumePutter _(rootVolume);
|
||||
|
||||
// set results
|
||||
if (error == B_OK) {
|
||||
*data = volumeManager;
|
||||
*rootID = rootVolume->GetRootID();
|
||||
} else {
|
||||
#ifdef DEBUG_OBJECT_TRACKING
|
||||
ObjectTracker::ExitDefault();
|
||||
#endif
|
||||
exit_debugging();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_unmount
|
||||
static
|
||||
int
|
||||
netfs_unmount(void *ns)
|
||||
{
|
||||
VolumeManager* volumeManager = (VolumeManager*)ns;
|
||||
|
||||
PRINT(("netfs_unmount()\n"));
|
||||
|
||||
volumeManager->UnmountRootVolume();
|
||||
delete volumeManager;
|
||||
|
||||
#ifdef DEBUG_OBJECT_TRACKING
|
||||
ObjectTracker::ExitDefault();
|
||||
#endif
|
||||
|
||||
PRINT(("netfs_unmount() done\n"));
|
||||
|
||||
exit_debugging();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// netfs_sync
|
||||
static
|
||||
int
|
||||
netfs_sync(void *ns)
|
||||
{
|
||||
VolumeManager* volumeManager = (VolumeManager*)ns;
|
||||
Volume* volume = volumeManager->GetRootVolume();
|
||||
VolumePutter _(volume);
|
||||
|
||||
PRINT(("netfs_sync(%p)\n", ns));
|
||||
|
||||
status_t error = B_BAD_VALUE;
|
||||
if (volume)
|
||||
error = volume->Sync();
|
||||
|
||||
PRINT(("netfs_sync() done: %lx \n", error));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_read_fs_stat
|
||||
static
|
||||
int
|
||||
netfs_read_fs_stat(void *ns, struct fs_info *info)
|
||||
{
|
||||
VolumeManager* volumeManager = (VolumeManager*)ns;
|
||||
Volume* volume = volumeManager->GetRootVolume();
|
||||
VolumePutter _(volume);
|
||||
|
||||
PRINT(("netfs_read_fs_stat(%p, %p)\n", ns, info));
|
||||
|
||||
status_t error = B_BAD_VALUE;
|
||||
if (volume)
|
||||
error = volume->ReadFSStat(info);
|
||||
|
||||
PRINT(("netfs_read_fs_stat() done: %lx \n", error));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_write_fs_stat
|
||||
static
|
||||
int
|
||||
netfs_write_fs_stat(void *ns, struct fs_info *info, long mask)
|
||||
{
|
||||
VolumeManager* volumeManager = (VolumeManager*)ns;
|
||||
Volume* volume = volumeManager->GetRootVolume();
|
||||
VolumePutter _(volume);
|
||||
|
||||
PRINT(("netfs_write_fs_stat(%p, %p, %ld)\n", ns, info, mask));
|
||||
|
||||
status_t error = B_BAD_VALUE;
|
||||
if (volume)
|
||||
error = volume->WriteFSStat(info, mask);
|
||||
|
||||
PRINT(("netfs_write_fs_stat() done: %lx \n", error));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- vnodes -----
|
||||
|
||||
// netfs_read_vnode
|
||||
static
|
||||
int
|
||||
netfs_read_vnode(void *ns, vnode_id vnid, char reenter, void **node)
|
||||
{
|
||||
VolumeManager* volumeManager = (VolumeManager*)ns;
|
||||
Volume* volume = volumeManager->GetVolume(vnid);
|
||||
VolumePutter _(volume);
|
||||
|
||||
PRINT(("netfs_read_vnode(%p, %Ld, %d, %p)\n", ns, vnid, reenter, node));
|
||||
|
||||
status_t error = B_BAD_VALUE;
|
||||
if (volume)
|
||||
error = volume->ReadVNode(vnid, reenter, (Node**)node);
|
||||
|
||||
PRINT(("netfs_read_vnode() done: (%lx, %p)\n", error, *node));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_write_vnode
|
||||
static
|
||||
int
|
||||
netfs_write_vnode(void *ns, void *_node, char reenter)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
// DANGER: If dbg_printf() is used, this thread will enter another FS and
|
||||
// even perform a write operation. The is dangerous here, since this hook
|
||||
// may be called out of the other FSs, since, for instance a put_vnode()
|
||||
// called from another FS may cause the VFS layer to free vnodes and thus
|
||||
// invoke this hook.
|
||||
// PRINT(("netfs_write_vnode(%p, %p, %d)\n", ns, node, reenter));
|
||||
status_t error = node->GetVolume()->WriteVNode(node, reenter);
|
||||
// PRINT(("netfs_write_vnode() done: %lx\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_remove_vnode
|
||||
static
|
||||
int
|
||||
netfs_remove_vnode(void *ns, void *_node, char reenter)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
// DANGER: See netfs_write_vnode().
|
||||
// PRINT(("netfs_remove_vnode(%p, %p, %d)\n", ns, node, reenter));
|
||||
status_t error = node->GetVolume()->RemoveVNode(node, reenter);
|
||||
// PRINT(("netfs_remove_vnode() done: %lx\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- nodes -----
|
||||
|
||||
// netfs_fsync
|
||||
static
|
||||
int
|
||||
netfs_fsync(void *ns, void *_node)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_fsync(%p, %p)\n", ns, node));
|
||||
status_t error = node->GetVolume()->FSync(node);
|
||||
PRINT(("netfs_fsync() done: %lx\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_read_stat
|
||||
static
|
||||
int
|
||||
netfs_read_stat(void *ns, void *_node, struct stat *st)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_read_stat(%p, %p, %p)\n", ns, node, st));
|
||||
status_t error = node->GetVolume()->ReadStat(node, st);
|
||||
PRINT(("netfs_read_stat() done: %lx\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_write_stat
|
||||
static
|
||||
int
|
||||
netfs_write_stat(void *ns, void *_node, struct stat *st, long mask)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_write_stat(%p, %p, %p, %ld)\n", ns, node, st, mask));
|
||||
status_t error = node->GetVolume()->WriteStat(node, st, mask);
|
||||
PRINT(("netfs_write_stat() done: %lx\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_access
|
||||
static
|
||||
int
|
||||
netfs_access(void *ns, void *_node, int mode)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_access(%p, %p, %d)\n", ns, node, mode));
|
||||
status_t error = node->GetVolume()->Access(node, mode);
|
||||
PRINT(("netfs_access() done: %lx\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- files -----
|
||||
|
||||
// netfs_create
|
||||
static
|
||||
int
|
||||
netfs_create(void *ns, void *_dir, const char *name, int openMode, int mode,
|
||||
vnode_id *vnid, void **cookie)
|
||||
{
|
||||
Node* dir = (Node*)_dir;
|
||||
PRINT(("netfs_create(%p, %p, `%s', %d, %d, %p, %p)\n", ns, dir,
|
||||
name, openMode, mode, vnid, cookie));
|
||||
status_t error = dir->GetVolume()->Create(dir, name, openMode, mode, vnid,
|
||||
cookie);
|
||||
PRINT(("netfs_create() done: (%lx, %Ld, %p)\n", error, *vnid,
|
||||
*cookie));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_open
|
||||
static
|
||||
int
|
||||
netfs_open(void *ns, void *_node, int openMode, void **cookie)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_open(%p, %p, %d)\n", ns, node, openMode));
|
||||
status_t error = node->GetVolume()->Open(node, openMode, cookie);
|
||||
PRINT(("netfs_open() done: (%lx, %p)\n", error, *cookie));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_close
|
||||
static
|
||||
int
|
||||
netfs_close(void *ns, void *_node, void *cookie)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_close(%p, %p, %p)\n", ns, node, cookie));
|
||||
status_t error = node->GetVolume()->Close(node, cookie);
|
||||
PRINT(("netfs_close() done: %lx\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_free_cookie
|
||||
static
|
||||
int
|
||||
netfs_free_cookie(void *ns, void *_node, void *cookie)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_free_cookie(%p, %p, %p)\n", ns, node, cookie));
|
||||
status_t error = node->GetVolume()->FreeCookie(node, cookie);
|
||||
PRINT(("netfs_free_cookie() done: %lx\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_read
|
||||
static
|
||||
int
|
||||
netfs_read(void *ns, void *_node, void *cookie, off_t pos, void *buffer,
|
||||
size_t *bufferSize)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_read(%p, %p, %p, %Ld, %p, %lu)\n", ns, node, cookie, pos,
|
||||
buffer, *bufferSize));
|
||||
status_t error = node->GetVolume()->Read(node, cookie, pos, buffer,
|
||||
*bufferSize, bufferSize);
|
||||
PRINT(("netfs_read() done: (%lx, %lu)\n", error, *bufferSize));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_write
|
||||
static
|
||||
int
|
||||
netfs_write(void *ns, void *_node, void *cookie, off_t pos,
|
||||
const void *buffer, size_t *bufferSize)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_write(%p, %p, %p, %Ld, %p, %lu)\n", ns, node, cookie, pos,
|
||||
buffer, *bufferSize));
|
||||
status_t error = node->GetVolume()->Write(node, cookie, pos, buffer,
|
||||
*bufferSize, bufferSize);
|
||||
PRINT(("netfs_write() done: (%lx, %lu)\n", error, *bufferSize));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_ioctl
|
||||
static
|
||||
int
|
||||
netfs_ioctl(void *ns, void *_node, void *cookie, int cmd, void *buffer,
|
||||
size_t bufferSize)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_ioctl(%p, %p, %p, %d, %p, %lu)\n", ns, node, cookie, cmd,
|
||||
buffer, bufferSize));
|
||||
status_t error = node->GetVolume()->IOCtl(node, cookie, cmd, buffer,
|
||||
bufferSize);
|
||||
PRINT(("netfs_ioctl() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_setflags
|
||||
//static
|
||||
//int
|
||||
//netfs_setflags(void *ns, void *_node, void *cookie, int flags)
|
||||
//{
|
||||
// Node* node = (Node*)_node;
|
||||
// PRINT(("netfs_setflags(%p, %p, %p, %d)\n", ns, node, cookie, flags));
|
||||
// status_t error = node->GetVolume()->SetFlags(node, cookie, flags);
|
||||
// PRINT(("netfs_setflags() done: (%lx)\n", error));
|
||||
// return error;
|
||||
//}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- hard links / symlinks -----
|
||||
|
||||
// netfs_link
|
||||
static
|
||||
int
|
||||
netfs_link(void *ns, void *_dir, const char *name, void *_node)
|
||||
{
|
||||
Node* dir = (Node*)_dir;
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_link(%p, %p, `%s', %p)\n", ns, dir, name, node));
|
||||
status_t error = dir->GetVolume()->Link(dir, name, node);
|
||||
PRINT(("netfs_link() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_unlink
|
||||
static
|
||||
int
|
||||
netfs_unlink(void *ns, void *_dir, const char *name)
|
||||
{
|
||||
Node* dir = (Node*)_dir;
|
||||
PRINT(("netfs_unlink(%p, %p, `%s')\n", ns, dir, name));
|
||||
status_t error = dir->GetVolume()->Unlink(dir, name);
|
||||
PRINT(("netfs_unlink() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_symlink
|
||||
static
|
||||
int
|
||||
netfs_symlink(void *ns, void *_dir, const char *name, const char *path)
|
||||
{
|
||||
Node* dir = (Node*)_dir;
|
||||
PRINT(("netfs_symlink(%p, %p, `%s', `%s')\n", ns, dir, name, path));
|
||||
status_t error = dir->GetVolume()->Symlink(dir, name, path);
|
||||
PRINT(("netfs_symlink() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_read_link
|
||||
static
|
||||
int
|
||||
netfs_read_link(void *ns, void *_node, char *buffer, size_t *bufferSize)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_read_link(%p, %p, %p, %lu)\n", ns, node, buffer,
|
||||
*bufferSize));
|
||||
status_t error = node->GetVolume()->ReadLink(node, buffer, *bufferSize,
|
||||
bufferSize);
|
||||
PRINT(("netfs_read_link() done: (%lx, %lu)\n", error, *bufferSize));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_rename
|
||||
static
|
||||
int
|
||||
netfs_rename(void *ns, void *_oldDir, const char *oldName, void *_newDir,
|
||||
const char *newName)
|
||||
{
|
||||
Node* oldDir = (Node*)_oldDir;
|
||||
Node* newDir = (Node*)_newDir;
|
||||
PRINT(("netfs_rename(%p, %p, `%s', %p, `%s')\n", ns, oldDir, oldName,
|
||||
newDir, newName));
|
||||
status_t error = oldDir->GetVolume()->Rename(oldDir, oldName,
|
||||
newDir, newName);
|
||||
PRINT(("netfs_rename() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- directories -----
|
||||
|
||||
// netfs_mkdir
|
||||
static
|
||||
int
|
||||
netfs_mkdir(void *ns, void *_dir, const char *name, int mode)
|
||||
{
|
||||
Node* dir = (Node*)_dir;
|
||||
PRINT(("netfs_mkdir(%p, %p, `%s', %d)\n", ns, dir, name, mode));
|
||||
status_t error = dir->GetVolume()->MkDir(dir, name, mode);
|
||||
PRINT(("netfs_mkdir() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_rmdir
|
||||
static
|
||||
int
|
||||
netfs_rmdir(void *ns, void *_dir, const char *name)
|
||||
{
|
||||
Node* dir = (Node*)_dir;
|
||||
PRINT(("netfs_rmdir(%p, %p, `%s')\n", ns, dir, name));
|
||||
status_t error = dir->GetVolume()->RmDir(dir, name);
|
||||
PRINT(("netfs_rmdir() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_open_dir
|
||||
static
|
||||
int
|
||||
netfs_open_dir(void *ns, void *_node, void **cookie)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_open_dir(%p, %p)\n", ns, node));
|
||||
status_t error = node->GetVolume()->OpenDir(node, cookie);
|
||||
PRINT(("netfs_open_dir() done: (%lx, %p)\n", error, *cookie));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_close_dir
|
||||
static
|
||||
int
|
||||
netfs_close_dir(void *ns, void *_node, void *cookie)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_close_dir(%p, %p, %p)\n", ns, node, cookie));
|
||||
status_t error = node->GetVolume()->CloseDir(node, cookie);
|
||||
PRINT(("netfs_close_dir() done: %lx\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_free_dir_cookie
|
||||
static
|
||||
int
|
||||
netfs_free_dir_cookie(void *ns, void *_node, void *cookie)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_free_dir_cookie(%p, %p, %p)\n", ns, node, cookie));
|
||||
status_t error = node->GetVolume()->FreeDirCookie(node, cookie);
|
||||
PRINT(("netfs_free_dir_cookie() done: %lx \n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_read_dir
|
||||
static
|
||||
int
|
||||
netfs_read_dir(void *ns, void *_node, void *cookie, long *count,
|
||||
struct dirent *buffer, size_t bufferSize)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_read_dir(%p, %p, %p, %ld, %p, %lu)\n", ns, node, cookie,
|
||||
*count, buffer, bufferSize));
|
||||
status_t error = node->GetVolume()->ReadDir(node, cookie, buffer,
|
||||
bufferSize, *count, count);
|
||||
PRINT(("netfs_read_dir() done: (%lx, %ld)\n", error, *count));
|
||||
#if DEBUG
|
||||
dirent* entry = buffer;
|
||||
for (int32 i = 0; i < *count; i++) {
|
||||
// R5's kernel vsprintf() doesn't seem to know `%.<number>s', so
|
||||
// we need to work around.
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
int nameLen = strnlen(entry->d_name, B_FILE_NAME_LENGTH - 1);
|
||||
strncpy(name, entry->d_name, nameLen);
|
||||
name[nameLen] = '\0';
|
||||
PRINT((" entry: d_dev: %ld, d_pdev: %ld, d_ino: %Ld, d_pino: %Ld, "
|
||||
"d_reclen: %hu, d_name: `%s'\n",
|
||||
entry->d_dev, entry->d_pdev, entry->d_ino, entry->d_pino,
|
||||
entry->d_reclen, name));
|
||||
entry = (dirent*)((char*)entry + entry->d_reclen);
|
||||
}
|
||||
#endif
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_rewind_dir
|
||||
static
|
||||
int
|
||||
netfs_rewind_dir(void *ns, void *_node, void *cookie)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_rewind_dir(%p, %p, %p)\n", ns, node, cookie));
|
||||
status_t error = node->GetVolume()->RewindDir(node, cookie);
|
||||
PRINT(("netfs_rewind_dir() done: %lx\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_walk
|
||||
static
|
||||
int
|
||||
netfs_walk(void *ns, void *_dir, const char *entryName,
|
||||
char **resolvedPath, vnode_id *vnid)
|
||||
{
|
||||
Node* dir = (Node*)_dir;
|
||||
PRINT(("netfs_walk(%p, %p, `%s', %p, %p)\n", ns, dir,
|
||||
entryName, resolvedPath, vnid));
|
||||
status_t error = dir->GetVolume()->Walk(dir, entryName, resolvedPath, vnid);
|
||||
PRINT(("netfs_walk() done: (%lx, `%s', %Ld)\n", error,
|
||||
(resolvedPath ? *resolvedPath : NULL), *vnid));
|
||||
return error;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- attributes -----
|
||||
|
||||
// netfs_open_attrdir
|
||||
static
|
||||
int
|
||||
netfs_open_attrdir(void *ns, void *_node, void **cookie)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_open_attrdir(%p, %p)\n", ns, node));
|
||||
status_t error = node->GetVolume()->OpenAttrDir(node, cookie);
|
||||
PRINT(("netfs_open_attrdir() done: (%lx, %p)\n", error, *cookie));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_close_attrdir
|
||||
static
|
||||
int
|
||||
netfs_close_attrdir(void *ns, void *_node, void *cookie)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_close_attrdir(%p, %p, %p)\n", ns, node, cookie));
|
||||
status_t error = node->GetVolume()->CloseAttrDir(node, cookie);
|
||||
PRINT(("netfs_close_attrdir() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_free_attrdir_cookie
|
||||
static
|
||||
int
|
||||
netfs_free_attrdir_cookie(void *ns, void *_node, void *cookie)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_free_attrdir_cookie(%p, %p, %p)\n", ns, node, cookie));
|
||||
status_t error = node->GetVolume()->FreeAttrDirCookie(node, cookie);
|
||||
PRINT(("netfs_free_attrdir_cookie() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_read_attrdir
|
||||
static
|
||||
int
|
||||
netfs_read_attrdir(void *ns, void *_node, void *cookie, long *count,
|
||||
struct dirent *buffer, size_t bufferSize)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_read_attrdir(%p, %p, %p, %ld, %p, %lu)\n", ns, node,
|
||||
cookie, *count, buffer, bufferSize));
|
||||
status_t error = node->GetVolume()->ReadAttrDir(node, cookie, buffer,
|
||||
bufferSize, *count, count);
|
||||
PRINT(("netfs_read_attrdir() done: (%lx, %ld)\n", error, *count));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_rewind_attrdir
|
||||
static
|
||||
int
|
||||
netfs_rewind_attrdir(void *ns, void *_node, void *cookie)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_rewind_attrdir(%p, %p, %p)\n", ns, node, cookie));
|
||||
status_t error = node->GetVolume()->RewindAttrDir(node, cookie);
|
||||
PRINT(("netfs_rewind_attrdir() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_read_attr
|
||||
static
|
||||
int
|
||||
netfs_read_attr(void *ns, void *_node, const char *name, int type,
|
||||
void *buffer, size_t *bufferSize, off_t pos)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_read_attr(%p, %p, `%s', %d, %p, %lu, %Ld)\n", ns, node,
|
||||
name, type, buffer, *bufferSize, pos));
|
||||
status_t error = node->GetVolume()->ReadAttr(node, name, type, pos, buffer,
|
||||
*bufferSize, bufferSize);
|
||||
PRINT(("netfs_read_attr() done: (%lx, %ld)\n", error, *bufferSize));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_write_attr
|
||||
static
|
||||
int
|
||||
netfs_write_attr(void *ns, void *_node, const char *name, int type,
|
||||
const void *buffer, size_t *bufferSize, off_t pos)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_write_attr(%p, %p, `%s', %d, %p, %lu, %Ld)\n", ns, node,
|
||||
name, type, buffer, *bufferSize, pos));
|
||||
status_t error = node->GetVolume()->WriteAttr(node, name, type, pos, buffer,
|
||||
*bufferSize, bufferSize);
|
||||
PRINT(("netfs_write_attr() done: (%lx, %ld)\n", error, *bufferSize));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_remove_attr
|
||||
static
|
||||
int
|
||||
netfs_remove_attr(void *ns, void *_node, const char *name)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_remove_attr(%p, %p, `%s')\n", ns, node, name));
|
||||
status_t error = node->GetVolume()->RemoveAttr(node, name);
|
||||
PRINT(("netfs_remove_attr() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_rename_attr
|
||||
static
|
||||
int
|
||||
netfs_rename_attr(void *ns, void *_node, const char *oldName,
|
||||
const char *newName)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_rename_attr(%p, %p, `%s', `%s')\n", ns, node, oldName,
|
||||
newName));
|
||||
status_t error = node->GetVolume()->RenameAttr(node, oldName, newName);
|
||||
PRINT(("netfs_rename_attr() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_stat_attr
|
||||
static
|
||||
int
|
||||
netfs_stat_attr(void *ns, void *_node, const char *name,
|
||||
struct attr_info *attrInfo)
|
||||
{
|
||||
Node* node = (Node*)_node;
|
||||
PRINT(("netfs_stat_attr(%p, %p, `%s', %p)\n", ns, node, name,
|
||||
attrInfo));
|
||||
status_t error = node->GetVolume()->StatAttr(node, name, attrInfo);
|
||||
PRINT(("netfs_stat_attr() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- queries -----
|
||||
|
||||
// netfs_open_query
|
||||
static
|
||||
int
|
||||
netfs_open_query(void *ns, const char *queryString, ulong flags,
|
||||
port_id port, long token, void **cookie)
|
||||
{
|
||||
VolumeManager* volumeManager = (VolumeManager*)ns;
|
||||
Volume* volume = volumeManager->GetRootVolume();
|
||||
VolumePutter _(volume);
|
||||
|
||||
PRINT(("netfs_open_query(%p, `%s', %lu, %ld, %ld, %p)\n", ns,
|
||||
queryString, flags, port, token, cookie));
|
||||
|
||||
status_t error = B_BAD_VALUE;
|
||||
if (volume) {
|
||||
error = volume->OpenQuery(queryString, flags, port, token,
|
||||
(QueryIterator**)cookie);
|
||||
}
|
||||
|
||||
PRINT(("netfs_open_query() done: (%lx, %p)\n", error, *cookie));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_close_query
|
||||
static
|
||||
int
|
||||
netfs_close_query(void *ns, void *cookie)
|
||||
{
|
||||
PRINT(("netfs_close_query(%p, %p)\n", ns, cookie));
|
||||
|
||||
status_t error = B_OK;
|
||||
// no-op: we don't use this hook
|
||||
|
||||
PRINT(("netfs_close_query() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_free_query_cookie
|
||||
static
|
||||
int
|
||||
netfs_free_query_cookie(void *ns, void *node, void *cookie)
|
||||
{
|
||||
VolumeManager* volumeManager = (VolumeManager*)ns;
|
||||
QueryIterator* iterator = (QueryIterator*)cookie;
|
||||
|
||||
PRINT(("netfs_free_query_cookie(%p, %p)\n", ns, cookie));
|
||||
|
||||
status_t error = B_OK;
|
||||
volumeManager->GetQueryManager()->PutIterator(iterator);
|
||||
|
||||
PRINT(("netfs_free_query_cookie() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// netfs_read_query
|
||||
static
|
||||
int
|
||||
netfs_read_query(void *ns, void *cookie, long *count,
|
||||
struct dirent *buffer, size_t bufferSize)
|
||||
{
|
||||
VolumeManager* volumeManager = (VolumeManager*)ns;
|
||||
Volume* volume = volumeManager->GetRootVolume();
|
||||
QueryIterator* iterator = (QueryIterator*)cookie;
|
||||
VolumePutter _(volume);
|
||||
|
||||
PRINT(("netfs_read_query(%p, %p, %ld, %p, %lu)\n", ns, cookie,
|
||||
*count, buffer, bufferSize));
|
||||
|
||||
status_t error = B_BAD_VALUE;
|
||||
if (volume) {
|
||||
error = volume->ReadQuery(iterator, buffer, bufferSize,
|
||||
*count, count);
|
||||
}
|
||||
|
||||
PRINT(("netfs_read_query() done: (%lx, %ld)\n", error, *count));
|
||||
return error;
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
// AuthenticationServerDefs.h
|
||||
|
||||
#ifndef AUTHENTICATION_SERVER_DEFS_H
|
||||
#define AUTHENTICATION_SERVER_DEFS_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
extern const char* kAuthenticationServerPortName;
|
||||
|
||||
#endif // AUTHENTICATION_SERVER_DEFS_H
|
@ -0,0 +1,22 @@
|
||||
// netfs_ioctl.h
|
||||
|
||||
#ifndef NET_FS_IOCTL_H
|
||||
#define NET_FS_IOCTL_H
|
||||
|
||||
// our ioctl commands
|
||||
enum {
|
||||
NET_FS_IOCTL_ADD_SERVER = 11000,
|
||||
NET_FS_IOCTL_REMOVE_SERVER,
|
||||
};
|
||||
|
||||
// parameter for NET_FS_IOCTL_ADD_SERVER
|
||||
struct netfs_ioctl_add_server {
|
||||
char serverName[256];
|
||||
};
|
||||
|
||||
// parameter for NET_FS_IOCTL_REMOVE_SERVER
|
||||
struct netfs_ioctl_remove_server {
|
||||
char serverName[256];
|
||||
};
|
||||
|
||||
#endif // NET_FS_IOCTL_H
|
@ -0,0 +1,149 @@
|
||||
// NetFSServerRosterDefs.h
|
||||
|
||||
#ifndef NET_FS_SERVER_ROSTER_DEFS_H
|
||||
#define NET_FS_SERVER_ROSTER_DEFS_H
|
||||
|
||||
extern const char* kNetFSServerSignature;
|
||||
|
||||
// message what field values
|
||||
enum {
|
||||
NETFS_REQUEST_GET_MESSENGER = 'nfgm',
|
||||
|
||||
NETFS_REQUEST_ADD_USER = 'nfau',
|
||||
NETFS_REQUEST_REMOVE_USER = 'nfru',
|
||||
NETFS_REQUEST_GET_USERS = 'nfgu',
|
||||
NETFS_REQUEST_GET_USER_STATISTICS = 'nfus',
|
||||
|
||||
NETFS_REQUEST_ADD_SHARE = 'nfas',
|
||||
NETFS_REQUEST_REMOVE_SHARE = 'nfrs',
|
||||
NETFS_REQUEST_GET_SHARES = 'nfgs',
|
||||
NETFS_REQUEST_GET_SHARE_USERS = 'nfsu',
|
||||
NETFS_REQUEST_GET_SHARE_STATISTICS = 'nfss',
|
||||
|
||||
NETFS_REQUEST_SET_USER_PERMISSIONS = 'nfsp',
|
||||
NETFS_REQUEST_GET_USER_PERMISSIONS = 'nfgp',
|
||||
|
||||
NETFS_REQUEST_SAVE_SETTINGS = 'nfse',
|
||||
};
|
||||
|
||||
/*
|
||||
Protocol
|
||||
========
|
||||
|
||||
Common
|
||||
------
|
||||
|
||||
reply:
|
||||
"error": int32
|
||||
|
||||
|
||||
NETFS_REQUEST_GET_MESSENGER
|
||||
---------------------------
|
||||
|
||||
reply:
|
||||
"messenger": messenger
|
||||
|
||||
|
||||
NETFS_REQUEST_ADD_USER
|
||||
----------------------
|
||||
|
||||
request:
|
||||
"user": string
|
||||
[ "password": string ]
|
||||
|
||||
|
||||
NETFS_REQUEST_REMOVE_USER
|
||||
-------------------------
|
||||
|
||||
request:
|
||||
"user": string
|
||||
|
||||
|
||||
NETFS_REQUEST_GET_USERS
|
||||
-----------------------
|
||||
|
||||
reply:
|
||||
"users": message ( "users": string[] )
|
||||
|
||||
|
||||
NETFS_REQUEST_GET_USER_STATISTICS
|
||||
---------------------------------
|
||||
|
||||
request:
|
||||
"user": string
|
||||
|
||||
reply:
|
||||
"statistics": message ( not defined yet )
|
||||
|
||||
|
||||
NETFS_REQUEST_ADD_SHARE
|
||||
-----------------------
|
||||
|
||||
request:
|
||||
"share": string
|
||||
"path": string
|
||||
|
||||
|
||||
NETFS_REQUEST_REMOVE_SHARE
|
||||
--------------------------
|
||||
|
||||
request:
|
||||
"share": string
|
||||
|
||||
|
||||
NETFS_REQUEST_GET_SHARES
|
||||
------------------------
|
||||
|
||||
reply:
|
||||
"shares": message ( "shares": string[]
|
||||
"paths": string[] )
|
||||
|
||||
|
||||
NETFS_REQUEST_GET_SHARE_USERS
|
||||
-----------------------------
|
||||
|
||||
request:
|
||||
"share": string
|
||||
|
||||
reply:
|
||||
"users": message ( "users": string[] )
|
||||
|
||||
|
||||
NETFS_REQUEST_GET_SHARE_STATISTICS
|
||||
----------------------------------
|
||||
|
||||
request:
|
||||
"share": string
|
||||
|
||||
reply:
|
||||
"statistics": message ( not defined yet )
|
||||
|
||||
|
||||
NETFS_REQUEST_SET_USER_PERMISSIONS
|
||||
----------------------------------
|
||||
|
||||
request:
|
||||
"share": string
|
||||
"user": string
|
||||
"permissions": int32
|
||||
|
||||
|
||||
NETFS_REQUEST_GET_USER_PERMISSIONS
|
||||
----------------------------------
|
||||
|
||||
request:
|
||||
"share": string
|
||||
"user": string
|
||||
|
||||
reply:
|
||||
"permissions": int32
|
||||
|
||||
|
||||
NETFS_REQUEST_SAVE_SETTINGS
|
||||
---------------------------
|
||||
|
||||
request: <empty>
|
||||
|
||||
*/
|
||||
|
||||
#endif // NET_FS_SERVER_ROSTER_DEFS_H
|
@ -0,0 +1,44 @@
|
||||
// AbstractConnection.h
|
||||
|
||||
#ifndef NET_FS_ABSTRACT_CONNECTION_H
|
||||
#define NET_FS_ABSTRACT_CONNECTION_H
|
||||
|
||||
#include "Connection.h"
|
||||
#include "Locker.h"
|
||||
#include "Vector.h"
|
||||
|
||||
class AbstractConnection : public Connection {
|
||||
protected:
|
||||
AbstractConnection();
|
||||
|
||||
public:
|
||||
virtual ~AbstractConnection();
|
||||
|
||||
virtual status_t Init(const char* parameters) = 0;
|
||||
status_t Init();
|
||||
virtual void Close();
|
||||
|
||||
// virtual User* GetAuthorizedUser();
|
||||
|
||||
status_t AddDownStreamChannel(Channel* channel);
|
||||
status_t AddUpStreamChannel(Channel* channel);
|
||||
|
||||
virtual int32 CountDownStreamChannels() const;
|
||||
virtual Channel* DownStreamChannelAt(int32 index) const;
|
||||
|
||||
virtual status_t GetUpStreamChannel(Channel** channel,
|
||||
bigtime_t timeout = B_INFINITE_TIMEOUT);
|
||||
virtual status_t PutUpStreamChannel(Channel* channel);
|
||||
|
||||
protected:
|
||||
typedef Vector<Channel*> ChannelVector;
|
||||
|
||||
status_t fInitStatus;
|
||||
ChannelVector fDownStreamChannels;
|
||||
sem_id fUpStreamChannelSemaphore;
|
||||
Locker fUpStreamChannelLock;
|
||||
ChannelVector fUpStreamChannels;
|
||||
int32 fFreeUpStreamChannels;
|
||||
};
|
||||
|
||||
#endif // NET_FS_ABSTRACT_CONNECTION_H
|
@ -0,0 +1,32 @@
|
||||
// AttrDirInfo.h
|
||||
|
||||
#ifndef NET_FS_ATTR_DIR_INFO_H
|
||||
#define NET_FS_ATTR_DIR_INFO_H
|
||||
|
||||
#include <fs_attr.h>
|
||||
|
||||
#include "RequestMemberArray.h"
|
||||
|
||||
// AttributeInfo
|
||||
struct AttributeInfo : public RequestMember {
|
||||
virtual void ShowAround(RequestMemberVisitor* visitor);
|
||||
|
||||
StringData name;
|
||||
struct attr_info info;
|
||||
Data data;
|
||||
};
|
||||
|
||||
// AttrDirInfo
|
||||
struct AttrDirInfo : public FlattenableRequestMember {
|
||||
AttrDirInfo();
|
||||
|
||||
virtual void ShowAround(RequestMemberVisitor* visitor);
|
||||
virtual status_t Flatten(RequestFlattener* flattener);
|
||||
virtual status_t Unflatten(RequestUnflattener* unflattener);
|
||||
|
||||
RequestMemberArray<AttributeInfo> attributeInfos;
|
||||
int64 revision;
|
||||
bool isValid;
|
||||
};
|
||||
|
||||
#endif // NET_FS_ATTR_DIR_INFO_H
|
@ -0,0 +1,35 @@
|
||||
// Blocker.h
|
||||
|
||||
#ifndef BLOCKER_H
|
||||
#define BLOCKER_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
class Blocker {
|
||||
public:
|
||||
Blocker();
|
||||
Blocker(sem_id semaphore);
|
||||
Blocker(const Blocker& other);
|
||||
~Blocker();
|
||||
|
||||
status_t InitCheck() const;
|
||||
|
||||
status_t PrepareForUse();
|
||||
|
||||
status_t Block(int32* userData = NULL);
|
||||
status_t Unblock(int32 userData = 0);
|
||||
|
||||
Blocker& operator=(const Blocker& other);
|
||||
bool operator==(const Blocker& other) const;
|
||||
bool operator!=(const Blocker& other) const;
|
||||
|
||||
private:
|
||||
void _Unset();
|
||||
|
||||
private:
|
||||
struct Data;
|
||||
|
||||
Data* fData;
|
||||
};
|
||||
|
||||
#endif // BLOCKER_H
|
@ -0,0 +1,51 @@
|
||||
// BlockerPool.h
|
||||
|
||||
#ifndef BLOCKER_POOL_H
|
||||
#define BLOCKER_POOL_H
|
||||
|
||||
#include "Blocker.h"
|
||||
#include "Locker.h"
|
||||
|
||||
class BlockerPool : public Locker {
|
||||
public:
|
||||
BlockerPool(int32 count = 10);
|
||||
~BlockerPool();
|
||||
|
||||
status_t InitCheck() const;
|
||||
|
||||
Blocker GetBlocker();
|
||||
status_t PutBlocker(Blocker blocker);
|
||||
|
||||
private:
|
||||
status_t _Init(int32 count);
|
||||
void _Unset();
|
||||
|
||||
private:
|
||||
struct BlockerVector;
|
||||
|
||||
sem_id fFreeBlockersSemaphore;
|
||||
BlockerVector* fBlockers;
|
||||
status_t fInitStatus;
|
||||
|
||||
};
|
||||
|
||||
// BlockerPutter
|
||||
class BlockerPutter {
|
||||
public:
|
||||
BlockerPutter(BlockerPool& pool, Blocker blocker)
|
||||
: fPool(pool),
|
||||
fBlocker(blocker)
|
||||
{
|
||||
}
|
||||
|
||||
~BlockerPutter()
|
||||
{
|
||||
fPool.PutBlocker(fBlocker);
|
||||
}
|
||||
|
||||
private:
|
||||
BlockerPool& fPool;
|
||||
Blocker fBlocker;
|
||||
};
|
||||
|
||||
#endif // BLOCKER_POOL_H
|
@ -0,0 +1,193 @@
|
||||
// BlockingQueue.h
|
||||
//
|
||||
// Copyright (c) 2004, Ingo Weinhold (bonefish@cs.tu-berlin.de)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// Except as contained in this notice, the name of a copyright holder shall
|
||||
// not be used in advertising or otherwise to promote the sale, use or other
|
||||
// dealings in this Software without prior written authorization of the
|
||||
// copyright holder.
|
||||
|
||||
#ifndef BLOCKING_QUEUE_H
|
||||
#define BLOCKING_QUEUE_H
|
||||
|
||||
#include <AutoLocker.h>
|
||||
#include <OS.h>
|
||||
|
||||
#include "DebugSupport.h"
|
||||
#include "Locker.h"
|
||||
#include "Vector.h"
|
||||
|
||||
template<typename Element>
|
||||
class BlockingQueue : public Locker {
|
||||
public:
|
||||
BlockingQueue(const char* name = NULL);
|
||||
~BlockingQueue();
|
||||
|
||||
status_t InitCheck() const;
|
||||
|
||||
status_t Close(bool deleteElements,
|
||||
const Vector<Element*>** elements = NULL);
|
||||
|
||||
status_t Push(Element* element);
|
||||
status_t Pop(Element** element,
|
||||
bigtime_t timeout = B_INFINITE_TIMEOUT);
|
||||
status_t Peek(Element** element);
|
||||
status_t Remove(Element* element);
|
||||
|
||||
int32 Size() const;
|
||||
|
||||
private:
|
||||
Vector<Element*> fElements;
|
||||
sem_id fElementSemaphore;
|
||||
};
|
||||
|
||||
// constructor
|
||||
template<typename Element>
|
||||
BlockingQueue<Element>::BlockingQueue(const char* name)
|
||||
: fElements(),
|
||||
fElementSemaphore(-1)
|
||||
{
|
||||
fElementSemaphore = create_sem(0, (name ? name : "blocking queue"));
|
||||
}
|
||||
|
||||
// destructor
|
||||
template<typename Element>
|
||||
BlockingQueue<Element>::~BlockingQueue()
|
||||
{
|
||||
if (fElementSemaphore >= 0)
|
||||
delete_sem(fElementSemaphore);
|
||||
}
|
||||
|
||||
// InitCheck
|
||||
template<typename Element>
|
||||
status_t
|
||||
BlockingQueue<Element>::InitCheck() const
|
||||
{
|
||||
return (fElementSemaphore < 0 ? fElementSemaphore : B_OK);
|
||||
}
|
||||
|
||||
// Close
|
||||
template<typename Element>
|
||||
status_t
|
||||
BlockingQueue<Element>::Close(bool deleteElements,
|
||||
const Vector<Element*>** elements)
|
||||
{
|
||||
AutoLocker<Locker> _(this);
|
||||
status_t error = delete_sem(fElementSemaphore);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
fElementSemaphore = -1;
|
||||
if (elements)
|
||||
*elements = &fElements;
|
||||
if (deleteElements) {
|
||||
int32 count = fElements.Count();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
delete fElements.ElementAt(i);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// Push
|
||||
template<typename Element>
|
||||
status_t
|
||||
BlockingQueue<Element>::Push(Element* element)
|
||||
{
|
||||
AutoLocker<Locker> _(this);
|
||||
if (fElementSemaphore < 0)
|
||||
return B_NO_INIT;
|
||||
status_t error = fElements.PushBack(element);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
error = release_sem(fElementSemaphore);
|
||||
if (error != B_OK)
|
||||
fElements.Erase(fElements.Count() - 1);
|
||||
return error;
|
||||
}
|
||||
|
||||
// Pop
|
||||
template<typename Element>
|
||||
status_t
|
||||
BlockingQueue<Element>::Pop(Element** element, bigtime_t timeout)
|
||||
{
|
||||
status_t error = acquire_sem_etc(fElementSemaphore, 1, B_RELATIVE_TIMEOUT,
|
||||
timeout);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
AutoLocker<Locker> _(this);
|
||||
if (fElementSemaphore < 0)
|
||||
return B_NO_INIT;
|
||||
int32 count = fElements.Count();
|
||||
if (count == 0)
|
||||
return B_ERROR;
|
||||
*element = fElements.ElementAt(0);
|
||||
fElements.Erase(0);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Peek
|
||||
template<typename Element>
|
||||
status_t
|
||||
BlockingQueue<Element>::Peek(Element** element)
|
||||
{
|
||||
AutoLocker<Locker> _(this);
|
||||
if (fElementSemaphore < 0)
|
||||
return B_NO_INIT;
|
||||
int32 count = fElements.Count();
|
||||
if (count == 0)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
*element = fElements.ElementAt(0);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Remove
|
||||
template<typename Element>
|
||||
status_t
|
||||
BlockingQueue<Element>::Remove(Element* element)
|
||||
{
|
||||
status_t error = acquire_sem_etc(fElementSemaphore, 1,
|
||||
B_RELATIVE_TIMEOUT, 0);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
AutoLocker<Locker> _(this);
|
||||
if (fElementSemaphore < 0)
|
||||
return B_NO_INIT;
|
||||
int32 count = fElements.Remove(element);
|
||||
if (count == 0) {
|
||||
release_sem(fElementSemaphore);
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
if (count > 1) {
|
||||
ERROR("ERROR: BlockingQueue::Remove(): Removed %ld elements!\n",
|
||||
count);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// Size
|
||||
template<typename Element>
|
||||
int32
|
||||
BlockingQueue<Element>::Size() const
|
||||
{
|
||||
AutoLocker<Locker> _(this);
|
||||
return (fElements.Count());
|
||||
}
|
||||
|
||||
#endif // BLOCKING_QUEUE_H
|
@ -0,0 +1,21 @@
|
||||
// Channel.h
|
||||
|
||||
#ifndef NET_FS_CHANNEL_H
|
||||
#define NET_FS_CHANNEL_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class Channel {
|
||||
protected:
|
||||
Channel();
|
||||
|
||||
public:
|
||||
virtual ~Channel();
|
||||
|
||||
virtual void Close() = 0;
|
||||
|
||||
virtual status_t Send(const void* buffer, int32 size) = 0;
|
||||
virtual status_t Receive(void* buffer, int32 size) = 0;
|
||||
};
|
||||
|
||||
#endif // NET_FS_CHANNEL_H
|
@ -0,0 +1,31 @@
|
||||
// Connection.h
|
||||
|
||||
#ifndef NET_FS_CONNECTION_H
|
||||
#define NET_FS_CONNECTION_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
class Channel;
|
||||
class SecurityContext;
|
||||
class User;
|
||||
|
||||
// Connection
|
||||
class Connection {
|
||||
protected:
|
||||
Connection();
|
||||
|
||||
public:
|
||||
virtual ~Connection();
|
||||
|
||||
virtual status_t Init(const char* parameters) = 0;
|
||||
virtual void Close() = 0;
|
||||
|
||||
virtual int32 CountDownStreamChannels() const = 0;
|
||||
virtual Channel* DownStreamChannelAt(int32 index) const = 0;
|
||||
|
||||
virtual status_t GetUpStreamChannel(Channel** channel,
|
||||
bigtime_t timeout = B_INFINITE_TIMEOUT) = 0;
|
||||
virtual status_t PutUpStreamChannel(Channel* channel) = 0;
|
||||
};
|
||||
|
||||
#endif // NET_FS_CONNECTION_H
|
@ -0,0 +1,21 @@
|
||||
// ConnectionFactory.h
|
||||
|
||||
#ifndef NET_FS_CONNECTION_FACTORY_H
|
||||
#define NET_FS_CONNECTION_FACTORY_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class Connection;
|
||||
class ConnectionListener;
|
||||
|
||||
class ConnectionFactory {
|
||||
public:
|
||||
ConnectionFactory();
|
||||
~ConnectionFactory();
|
||||
|
||||
status_t CreateConnection(const char* type,
|
||||
const char* parameters,
|
||||
Connection** connection);
|
||||
};
|
||||
|
||||
#endif // NET_FS_CONNECTION_FACTORY_H
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Copyright 200?, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef DEBUG_SUPPORT_H
|
||||
#define DEBUG_SUPPORT_H
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#if !USER
|
||||
# include <KernelExport.h>
|
||||
#endif
|
||||
#include <OS.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
// define all macros we work with -- undefined macros are set to defaults
|
||||
#ifndef USER
|
||||
# define USER 0
|
||||
#endif
|
||||
#ifndef DEBUG
|
||||
# define DEBUG 0
|
||||
#endif
|
||||
#if !DEBUG
|
||||
# undef DEBUG_PRINT
|
||||
# define DEBUG_PRINT 0
|
||||
#endif
|
||||
#ifndef DEBUG_PRINT
|
||||
# define DEBUG_PRINT 0
|
||||
#endif
|
||||
#ifndef DEBUG_APP
|
||||
# define DEBUG_APP "packagefs"
|
||||
#endif
|
||||
#ifndef DEBUG_PRINT_FILE
|
||||
# define DEBUG_PRINT_FILE "/var/log/" DEBUG_APP ".log"
|
||||
#endif
|
||||
|
||||
|
||||
// define the debug output function
|
||||
#if USER
|
||||
# include <stdio.h>
|
||||
# if DEBUG_PRINT
|
||||
# define __out dbg_printf
|
||||
# else
|
||||
# define __out printf
|
||||
# endif
|
||||
#else
|
||||
# include <KernelExport.h>
|
||||
# include <null.h>
|
||||
# if DEBUG_PRINT
|
||||
# define __out dbg_printf
|
||||
# else
|
||||
# define __out dprintf
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// define the PANIC() macro
|
||||
#ifndef PANIC
|
||||
# if USER
|
||||
# define PANIC(str) debugger(str)
|
||||
# else
|
||||
# define PANIC(str) panic(str)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// functions exported by this module
|
||||
status_t init_debugging();
|
||||
status_t exit_debugging();
|
||||
void dbg_printf_begin();
|
||||
void dbg_printf_end();
|
||||
#if DEBUG_PRINT
|
||||
void dbg_printf(const char *format,...);
|
||||
#else
|
||||
static inline void dbg_printf(const char *,...) {}
|
||||
#endif
|
||||
|
||||
|
||||
// Short overview over the debug output macros:
|
||||
// PRINT()
|
||||
// is for general messages that very unlikely should appear in a release
|
||||
// build
|
||||
// FATAL()
|
||||
// this is for fatal messages, when something has really gone wrong
|
||||
// INFORM()
|
||||
// general information, as disk size, etc.
|
||||
// REPORT_ERROR(status_t)
|
||||
// prints out error information
|
||||
// RETURN_ERROR(status_t)
|
||||
// calls REPORT_ERROR() and return the value
|
||||
// D()
|
||||
// the statements in D() are only included if DEBUG is defined
|
||||
|
||||
|
||||
#define DEBUG_THREAD find_thread(NULL)
|
||||
#define DEBUG_CONTEXT(x) \
|
||||
{ \
|
||||
dbg_printf_begin(); \
|
||||
__out(DEBUG_APP " [%Ld: %5ld] ", system_time(), DEBUG_THREAD); \
|
||||
x; \
|
||||
dbg_printf_end(); \
|
||||
}
|
||||
#define DEBUG_CONTEXT_FUNCTION(prefix, x) \
|
||||
{ \
|
||||
dbg_printf_begin(); \
|
||||
__out(DEBUG_APP " [%Ld: %5ld] %s" prefix, system_time(), DEBUG_THREAD, \
|
||||
__PRETTY_FUNCTION__); \
|
||||
x; \
|
||||
dbg_printf_end(); \
|
||||
}
|
||||
#define DEBUG_CONTEXT_LINE(x) \
|
||||
{ \
|
||||
dbg_printf_begin(); \
|
||||
__out(DEBUG_APP " [%Ld: %5ld] %s:%d: ", system_time(), DEBUG_THREAD, \
|
||||
__PRETTY_FUNCTION__, __LINE__); \
|
||||
x; \
|
||||
dbg_printf_end(); \
|
||||
}
|
||||
|
||||
#define TPRINT(x...) DEBUG_CONTEXT( __out(x) )
|
||||
#define TREPORT_ERROR(status) \
|
||||
DEBUG_CONTEXT_LINE( __out("%s\n", strerror(status)) )
|
||||
#define TRETURN_ERROR(err) \
|
||||
{ \
|
||||
status_t _status = err; \
|
||||
if (_status < B_OK) \
|
||||
TREPORT_ERROR(_status); \
|
||||
return _status; \
|
||||
}
|
||||
#define TSET_ERROR(var, err) \
|
||||
{ \
|
||||
status_t _status = err; \
|
||||
if (_status < B_OK) \
|
||||
TREPORT_ERROR(_status); \
|
||||
var = _status; \
|
||||
}
|
||||
#define TFUNCTION(x...) DEBUG_CONTEXT_FUNCTION( ": ", __out(x) )
|
||||
#define TFUNCTION_START() DEBUG_CONTEXT_FUNCTION( "\n", )
|
||||
#define TFUNCTION_END() DEBUG_CONTEXT_FUNCTION( " done\n", )
|
||||
|
||||
#if DEBUG
|
||||
#define PRINT(x...) TPRINT(x)
|
||||
#define REPORT_ERROR(status) TREPORT_ERROR(status)
|
||||
#define RETURN_ERROR(err) TRETURN_ERROR(err)
|
||||
#define SET_ERROR(var, err) TSET_ERROR(var, err)
|
||||
#define FATAL(x...) DEBUG_CONTEXT( __out(x) )
|
||||
#define ERROR(x...) DEBUG_CONTEXT( __out(x) )
|
||||
#define WARN(x...) DEBUG_CONTEXT( __out(x) )
|
||||
#define INFORM(x...) DEBUG_CONTEXT( __out(x) )
|
||||
#define FUNCTION(x...) TFUNCTION(x)
|
||||
#define FUNCTION_START() TFUNCTION_START()
|
||||
#define FUNCTION_END() TFUNCTION_END()
|
||||
#define DARG(x) x
|
||||
#define D(x) {x;};
|
||||
#else
|
||||
#define PRINT(x...) ;
|
||||
#define REPORT_ERROR(status) ;
|
||||
#define RETURN_ERROR(status) return status;
|
||||
#define SET_ERROR(var, err) var = err;
|
||||
#define FATAL(x...) DEBUG_CONTEXT( __out(x) )
|
||||
#define ERROR(x...) DEBUG_CONTEXT( __out(x) )
|
||||
#define WARN(x...) DEBUG_CONTEXT( __out(x) )
|
||||
#define INFORM(x...) DEBUG_CONTEXT( __out(x) )
|
||||
#define FUNCTION(x...) ;
|
||||
#define FUNCTION_START() ;
|
||||
#define FUNCTION_END() ;
|
||||
#define DARG(x)
|
||||
#define D(x) ;
|
||||
#endif
|
||||
|
||||
#ifndef TOUCH
|
||||
#define TOUCH(var) (void)var
|
||||
#endif
|
||||
|
||||
|
||||
#endif // DEBUG_SUPPORT_H
|
@ -0,0 +1,17 @@
|
||||
// EntryInfo.h
|
||||
|
||||
#ifndef NET_FS_ENTRY_INFO_H
|
||||
#define NET_FS_ENTRY_INFO_H
|
||||
|
||||
#include "NodeInfo.h"
|
||||
#include "Request.h"
|
||||
|
||||
struct EntryInfo : public RequestMember {
|
||||
virtual void ShowAround(RequestMemberVisitor* visitor);
|
||||
|
||||
NodeID directoryID;
|
||||
StringData name;
|
||||
NodeInfo nodeInfo;
|
||||
};
|
||||
|
||||
#endif // NET_FS_ENTRY_INFO_H
|
@ -0,0 +1,20 @@
|
||||
// FSObject.h
|
||||
|
||||
#ifndef NET_FS_FS_OBJECT_H
|
||||
#define NET_FS_FS_OBJECT_H
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
class FSObject : public BReferenceable {
|
||||
public:
|
||||
FSObject();
|
||||
virtual ~FSObject();
|
||||
|
||||
void MarkRemoved();
|
||||
bool IsRemoved() const;
|
||||
|
||||
private:
|
||||
bool fRemoved;
|
||||
};
|
||||
|
||||
#endif // NET_FS_FS_OBJECT_H
|
@ -0,0 +1,27 @@
|
||||
// InsecureChannel.h
|
||||
|
||||
#ifndef NET_FS_INSECURE_CHANNEL_H
|
||||
#define NET_FS_INSECURE_CHANNEL_H
|
||||
|
||||
#include "Channel.h"
|
||||
|
||||
class NetAddress;
|
||||
|
||||
class InsecureChannel : public Channel {
|
||||
public:
|
||||
InsecureChannel(int socket);
|
||||
virtual ~InsecureChannel();
|
||||
|
||||
virtual void Close();
|
||||
|
||||
virtual status_t Send(const void* buffer, int32 size);
|
||||
virtual status_t Receive(void* buffer, int32 size);
|
||||
|
||||
status_t GetPeerAddress(NetAddress *address) const;
|
||||
|
||||
private:
|
||||
vint32 fSocket;
|
||||
bool fClosed;
|
||||
};
|
||||
|
||||
#endif // NET_FS_INSECURE_CHANNEL_H
|
@ -0,0 +1,66 @@
|
||||
// InsecureConnection.h
|
||||
|
||||
#ifndef NET_FS_INSECURE_CONNECTION_H
|
||||
#define NET_FS_INSECURE_CONNECTION_H
|
||||
|
||||
#ifdef HAIKU_TARGET_PLATFORM_BEOS
|
||||
# include <socket.h>
|
||||
#else
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include "AbstractConnection.h"
|
||||
|
||||
// InsecureConnection
|
||||
class InsecureConnection : public AbstractConnection {
|
||||
public:
|
||||
InsecureConnection();
|
||||
virtual ~InsecureConnection();
|
||||
|
||||
status_t Init(int socket); // server side
|
||||
virtual status_t Init(const char* parameters); // client side
|
||||
|
||||
status_t FinishInitialization();
|
||||
|
||||
private:
|
||||
status_t _OpenClientChannel(in_addr serverAddr,
|
||||
uint16 port, Channel** channel);
|
||||
|
||||
status_t _SendErrorReply(Channel* channel,
|
||||
status_t error);
|
||||
};
|
||||
|
||||
// InsecureConnectionDefs
|
||||
namespace InsecureConnectionDefs {
|
||||
|
||||
// ConnectRequest
|
||||
struct ConnectRequest {
|
||||
int32 protocolVersion;
|
||||
uint32 serverAddress;
|
||||
int32 upStreamChannels;
|
||||
int32 downStreamChannels;
|
||||
};
|
||||
|
||||
// ConnectReply
|
||||
struct ConnectReply {
|
||||
int32 error;
|
||||
int32 upStreamChannels;
|
||||
int32 downStreamChannels;
|
||||
uint16 port;
|
||||
};
|
||||
|
||||
extern const int32 kProtocolVersion;
|
||||
extern const bigtime_t kAcceptingTimeout;
|
||||
|
||||
// number of client up/down stream channels
|
||||
extern const int32 kMinUpStreamChannels;
|
||||
extern const int32 kMaxUpStreamChannels;
|
||||
extern const int32 kDefaultUpStreamChannels;
|
||||
extern const int32 kMinDownStreamChannels;
|
||||
extern const int32 kMaxDownStreamChannels;
|
||||
extern const int32 kDefaultDownStreamChannels;
|
||||
|
||||
} // namespace InsecureConnectionDefs
|
||||
|
||||
#endif // NET_FS_INSECURE_CONNECTION_H
|
@ -0,0 +1,72 @@
|
||||
// NetAddress.h
|
||||
|
||||
#ifndef NET_FS_NET_ADDRESS_H
|
||||
#define NET_FS_NET_ADDRESS_H
|
||||
|
||||
#ifdef HAIKU_TARGET_PLATFORM_BEOS
|
||||
# include <socket.h>
|
||||
#else
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
namespace BPrivate {
|
||||
class HashString;
|
||||
};
|
||||
using BPrivate::HashString;
|
||||
|
||||
// NetAddress
|
||||
class NetAddress {
|
||||
public:
|
||||
NetAddress();
|
||||
NetAddress(const sockaddr_in& address);
|
||||
NetAddress(const NetAddress& address);
|
||||
|
||||
void SetIP(int32 address);
|
||||
int32 GetIP() const;
|
||||
|
||||
void SetPort(uint16 port);
|
||||
uint16 GetPort() const;
|
||||
|
||||
void SetAddress(const sockaddr_in& address);
|
||||
const sockaddr_in& GetAddress() const;
|
||||
|
||||
bool IsLocal() const;
|
||||
|
||||
status_t GetString(HashString* string,
|
||||
bool includePort = true) const;
|
||||
|
||||
uint32 GetHashCode() const;
|
||||
|
||||
NetAddress& operator=(const NetAddress& address);
|
||||
bool operator==(const NetAddress& address) const;
|
||||
bool operator!=(const NetAddress& address) const;
|
||||
|
||||
private:
|
||||
sockaddr_in fAddress;
|
||||
};
|
||||
|
||||
// NetAddressResolver
|
||||
class NetAddressResolver {
|
||||
public:
|
||||
NetAddressResolver();
|
||||
~NetAddressResolver();
|
||||
|
||||
status_t InitCheck() const;
|
||||
|
||||
status_t GetHostAddress(const char* hostName,
|
||||
NetAddress* address);
|
||||
|
||||
private:
|
||||
class Resolver;
|
||||
|
||||
static void _Lock();
|
||||
static void _Unlock();
|
||||
|
||||
Resolver* fResolver;
|
||||
|
||||
static Resolver* volatile sResolver;
|
||||
static vint32 sLockCounter;
|
||||
};
|
||||
|
||||
#endif // NET_FS_NET_ADDRESS_H
|
@ -0,0 +1,38 @@
|
||||
// NetFSDefs.h
|
||||
|
||||
#ifndef NET_FS_DEFS_H
|
||||
#define NET_FS_DEFS_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
extern const uint16 kDefaultInsecureConnectionPort;
|
||||
extern const uint16 kDefaultBroadcastPort;
|
||||
extern const uint16 kDefaultServerInfoPort;
|
||||
|
||||
struct BroadcastMessage {
|
||||
uint32 magic;
|
||||
int32 protocolVersion;
|
||||
uint32 message;
|
||||
};
|
||||
|
||||
// version of the general NetFS protocol (the request stuff)
|
||||
enum {
|
||||
NETFS_PROTOCOL_VERSION = 1,
|
||||
};
|
||||
|
||||
// BroadcastMessage::magic value
|
||||
enum {
|
||||
BROADCAST_MESSAGE_MAGIC = 'BcMc',
|
||||
};
|
||||
|
||||
// BroadcastMessage::message values
|
||||
enum {
|
||||
BROADCAST_MESSAGE_SERVER_TICK = 0, // periodical tick
|
||||
BROADCAST_MESSAGE_SERVER_UPDATE = 1, // shares have changed
|
||||
BROADCAST_MESSAGE_CLIENT_HELLO = 2, // client requests server tick
|
||||
};
|
||||
|
||||
extern const bigtime_t kBroadcastingInterval;
|
||||
extern const bigtime_t kMinBroadcastingInterval;
|
||||
|
||||
#endif // NET_FS_DEFS_H
|
@ -0,0 +1,28 @@
|
||||
// NodeInfo.h
|
||||
|
||||
#ifndef NET_FS_NODE_INFO_H
|
||||
#define NET_FS_NODE_INFO_H
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "Request.h"
|
||||
#include "ServerNodeID.h"
|
||||
|
||||
struct NodeInfo : public RequestMember {
|
||||
virtual void ShowAround(RequestMemberVisitor* visitor);
|
||||
|
||||
inline NodeID GetID() const;
|
||||
|
||||
struct stat st;
|
||||
int64 revision;
|
||||
};
|
||||
|
||||
// GetID
|
||||
inline
|
||||
NodeID
|
||||
NodeInfo::GetID() const
|
||||
{
|
||||
return NodeID(st.st_dev, st.st_ino);
|
||||
}
|
||||
|
||||
#endif // NET_FS_NODE_INFO_H
|
@ -0,0 +1,193 @@
|
||||
// Permissions.h
|
||||
|
||||
#ifndef NET_FS_PERMISSIONS_H
|
||||
#define NET_FS_PERMISSIONS_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
enum {
|
||||
// file permissions
|
||||
READ_PERMISSION = 0x01,
|
||||
WRITE_PERMISSION = 0x02,
|
||||
|
||||
// directory permissions
|
||||
READ_DIR_PERMISSION = 0x04,
|
||||
WRITE_DIR_PERMISSION = 0x08,
|
||||
RESOLVE_DIR_ENTRY_PERMISSION = 0x10,
|
||||
|
||||
// share permissions
|
||||
MOUNT_SHARE_PERMISSION = 0x20,
|
||||
QUERY_SHARE_PERMISSION = 0x40,
|
||||
|
||||
// all permissions
|
||||
ALL_PERMISSIONS = 0x7f,
|
||||
};
|
||||
|
||||
class Permissions {
|
||||
public:
|
||||
inline Permissions();
|
||||
inline Permissions(uint32 permissions);
|
||||
inline Permissions(const Permissions& other);
|
||||
|
||||
inline uint32 GetPermissions() const;
|
||||
|
||||
inline Permissions& AddPermissions(uint32 permissions);
|
||||
inline Permissions& AddPermissions(Permissions permissions);
|
||||
|
||||
inline bool Implies(uint32 permissions) const;
|
||||
|
||||
inline bool ImpliesReadPermission() const;
|
||||
inline bool ImpliesWritePermission() const;
|
||||
inline bool ImpliesReadDirPermission() const;
|
||||
inline bool ImpliesWriteDirPermission() const;
|
||||
inline bool ImpliesResolveDirEntryPermission() const;
|
||||
inline bool ImpliesMountSharePermission() const;
|
||||
inline bool ImpliesQuerySharePermission() const;
|
||||
|
||||
inline Permissions& operator=(const Permissions& other);
|
||||
inline bool operator==(const Permissions& other) const;
|
||||
inline bool operator!=(const Permissions& other) const;
|
||||
|
||||
private:
|
||||
uint32 fPermissions;
|
||||
};
|
||||
|
||||
// inline implementation
|
||||
|
||||
// constructor
|
||||
inline
|
||||
Permissions::Permissions()
|
||||
: fPermissions(0)
|
||||
{
|
||||
}
|
||||
|
||||
// constructor
|
||||
inline
|
||||
Permissions::Permissions(uint32 permissions)
|
||||
: fPermissions(permissions)
|
||||
{
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
inline
|
||||
Permissions::Permissions(const Permissions& other)
|
||||
: fPermissions(other.fPermissions)
|
||||
{
|
||||
}
|
||||
|
||||
// GetPermissions
|
||||
inline
|
||||
uint32
|
||||
Permissions::GetPermissions() const
|
||||
{
|
||||
return fPermissions;
|
||||
}
|
||||
|
||||
// AddPermissions
|
||||
inline
|
||||
Permissions&
|
||||
Permissions::AddPermissions(uint32 permissions)
|
||||
{
|
||||
fPermissions |= permissions;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// AddPermissions
|
||||
inline
|
||||
Permissions&
|
||||
Permissions::AddPermissions(Permissions permissions)
|
||||
{
|
||||
fPermissions |= permissions.fPermissions;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Implies
|
||||
inline
|
||||
bool
|
||||
Permissions::Implies(uint32 permissions) const
|
||||
{
|
||||
return ((fPermissions & permissions) == permissions);
|
||||
}
|
||||
|
||||
// ImpliesReadPermission
|
||||
inline
|
||||
bool
|
||||
Permissions::ImpliesReadPermission() const
|
||||
{
|
||||
return Implies(READ_PERMISSION);
|
||||
}
|
||||
|
||||
// ImpliesWritePermission
|
||||
inline
|
||||
bool
|
||||
Permissions::ImpliesWritePermission() const
|
||||
{
|
||||
return Implies(WRITE_PERMISSION);
|
||||
}
|
||||
|
||||
// ImpliesReadDirPermission
|
||||
inline
|
||||
bool
|
||||
Permissions::ImpliesReadDirPermission() const
|
||||
{
|
||||
return Implies(READ_DIR_PERMISSION);
|
||||
}
|
||||
|
||||
// ImpliesWriteDirPermission
|
||||
inline
|
||||
bool
|
||||
Permissions::ImpliesWriteDirPermission() const
|
||||
{
|
||||
return Implies(WRITE_DIR_PERMISSION);
|
||||
}
|
||||
|
||||
// ImpliesResolveDirEntryPermission
|
||||
inline
|
||||
bool
|
||||
Permissions::ImpliesResolveDirEntryPermission() const
|
||||
{
|
||||
return Implies(RESOLVE_DIR_ENTRY_PERMISSION);
|
||||
}
|
||||
|
||||
// ImpliesMountSharePermission
|
||||
inline
|
||||
bool
|
||||
Permissions::ImpliesMountSharePermission() const
|
||||
{
|
||||
return Implies(MOUNT_SHARE_PERMISSION);
|
||||
}
|
||||
|
||||
// ImpliesQuerySharePermission
|
||||
inline
|
||||
bool
|
||||
Permissions::ImpliesQuerySharePermission() const
|
||||
{
|
||||
return Implies(QUERY_SHARE_PERMISSION);
|
||||
}
|
||||
|
||||
// =
|
||||
inline
|
||||
Permissions&
|
||||
Permissions::operator=(const Permissions& other)
|
||||
{
|
||||
fPermissions = other.fPermissions;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ==
|
||||
inline
|
||||
bool
|
||||
Permissions::operator==(const Permissions& other) const
|
||||
{
|
||||
return (fPermissions == other.fPermissions);
|
||||
}
|
||||
|
||||
// !=
|
||||
inline
|
||||
bool
|
||||
Permissions::operator!=(const Permissions& other) const
|
||||
{
|
||||
return (fPermissions != other.fPermissions);
|
||||
}
|
||||
|
||||
#endif // NET_FS_PERMISSIONS_H
|
@ -0,0 +1,41 @@
|
||||
// PortChannel.h
|
||||
|
||||
#ifndef NET_FS_PORT_CHANNEL_H
|
||||
#define NET_FS_PORT_CHANNEL_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include "Channel.h"
|
||||
|
||||
class PortChannel : public Channel {
|
||||
public:
|
||||
struct Info {
|
||||
port_id sendPort;
|
||||
port_id receivePort;
|
||||
};
|
||||
|
||||
public:
|
||||
PortChannel();
|
||||
PortChannel(const Info* info, bool inverse);
|
||||
PortChannel(port_id sendPort,
|
||||
port_id receivePort);
|
||||
virtual ~PortChannel();
|
||||
|
||||
status_t InitCheck() const;
|
||||
void GetInfo(Info* info) const;
|
||||
|
||||
virtual void Close();
|
||||
|
||||
virtual status_t Send(const void* buffer, int32 size);
|
||||
virtual status_t Receive(void* buffer, int32 size);
|
||||
|
||||
private:
|
||||
port_id fSendPort;
|
||||
port_id fReceivePort;
|
||||
uint8* fBuffer;
|
||||
int32 fBufferSize;
|
||||
int32 fBufferOffset;
|
||||
int32 fBufferContentSize;
|
||||
};
|
||||
|
||||
#endif // NET_FS_PORT_CHANNEL_H
|
@ -0,0 +1,63 @@
|
||||
// PortConnection.h
|
||||
|
||||
#ifndef NET_FS_PORT_CONNECTION_H
|
||||
#define NET_FS_PORT_CONNECTION_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include "AbstractConnection.h"
|
||||
#include "PortChannel.h"
|
||||
|
||||
// PortConnection
|
||||
class PortConnection : public AbstractConnection {
|
||||
public:
|
||||
PortConnection();
|
||||
virtual ~PortConnection();
|
||||
|
||||
status_t Init(Channel* channel, int32 upStreamChannels,
|
||||
int32 downStreamChannels); // server side
|
||||
virtual status_t Init(const char* parameters); // client side
|
||||
|
||||
status_t FinishInitialization();
|
||||
|
||||
private:
|
||||
static status_t _CreateChannel(PortChannel** channel,
|
||||
PortChannel::Info* info = NULL,
|
||||
bool inverse = false);
|
||||
|
||||
private:
|
||||
int32 fUpStreamChannels;
|
||||
int32 fDownStreamChannels;
|
||||
};
|
||||
|
||||
// PortConnectionDefs
|
||||
namespace PortConnectionDefs {
|
||||
|
||||
// ConnectRequest
|
||||
struct ConnectRequest {
|
||||
int32 protocolVersion;
|
||||
int32 upStreamChannels;
|
||||
int32 downStreamChannels;
|
||||
PortChannel::Info channelInfo;
|
||||
};
|
||||
|
||||
// ConnectReply
|
||||
struct ConnectReply {
|
||||
int32 error;
|
||||
int32 upStreamChannels;
|
||||
int32 downStreamChannels;
|
||||
};
|
||||
|
||||
extern const int32 kProtocolVersion;
|
||||
extern const char* kPortConnectionPortName;
|
||||
|
||||
// number of client up/down stream channels
|
||||
extern const int32 kMinUpStreamChannels;
|
||||
extern const int32 kMaxUpStreamChannels;
|
||||
extern const int32 kDefaultUpStreamChannels;
|
||||
extern const int32 kMinDownStreamChannels;
|
||||
extern const int32 kMaxDownStreamChannels;
|
||||
extern const int32 kDefaultDownStreamChannels;
|
||||
}
|
||||
|
||||
#endif // NET_FS_PORT_CONNECTION_H
|
136
src/add-ons/kernel/file_systems/netfs/headers/shared/Request.h
Normal file
136
src/add-ons/kernel/file_systems/netfs/headers/shared/Request.h
Normal file
@ -0,0 +1,136 @@
|
||||
// Request.h
|
||||
|
||||
#ifndef NET_FS_REQUEST_H
|
||||
#define NET_FS_REQUEST_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <HashString.h>
|
||||
|
||||
#include "SLList.h"
|
||||
|
||||
class RequestFlattener;
|
||||
class RequestMemberVisitor;
|
||||
class RequestUnflattener;
|
||||
class RequestVisitor;
|
||||
|
||||
// Data
|
||||
struct Data {
|
||||
const void* address;
|
||||
int32 size;
|
||||
|
||||
Data() : address(NULL), size(0) {}
|
||||
|
||||
void SetTo(const void* address, int32 size)
|
||||
{
|
||||
this->address = (size > 0 ? address : NULL);
|
||||
this->size = size;
|
||||
}
|
||||
|
||||
const void* GetData() const
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
int32 GetSize() const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
// StringData
|
||||
struct StringData : Data {
|
||||
void SetTo(const char* string)
|
||||
{
|
||||
Data::SetTo(string, (string ? strlen(string) + 1 : 0));
|
||||
}
|
||||
|
||||
void SetTo(const HashString& string)
|
||||
{
|
||||
SetTo(string.GetString());
|
||||
}
|
||||
|
||||
const char* GetString() const
|
||||
{
|
||||
return (const char*)address;
|
||||
}
|
||||
};
|
||||
|
||||
// RequestMember
|
||||
class RequestMember {
|
||||
public:
|
||||
RequestMember();
|
||||
virtual ~RequestMember();
|
||||
|
||||
virtual void ShowAround(RequestMemberVisitor* visitor) = 0;
|
||||
};
|
||||
|
||||
// FlattenableRequestMember
|
||||
class FlattenableRequestMember : public RequestMember {
|
||||
public:
|
||||
FlattenableRequestMember();
|
||||
virtual ~FlattenableRequestMember();
|
||||
|
||||
virtual status_t Flatten(RequestFlattener* flattener) = 0;
|
||||
virtual status_t Unflatten(RequestUnflattener* unflattener) = 0;
|
||||
};
|
||||
|
||||
// RequestBuffer
|
||||
class RequestBuffer : public SLListLinkImpl<RequestBuffer> {
|
||||
private:
|
||||
RequestBuffer() {}
|
||||
~RequestBuffer() {}
|
||||
|
||||
public:
|
||||
static RequestBuffer* Create(uint32 dataSize);
|
||||
static void Delete(RequestBuffer* buffer);
|
||||
|
||||
void* GetData();
|
||||
const void* GetData() const;
|
||||
};
|
||||
|
||||
// Request
|
||||
class Request : public FlattenableRequestMember {
|
||||
public:
|
||||
Request(uint32 type);
|
||||
virtual ~Request();
|
||||
|
||||
uint32 GetType() const;
|
||||
|
||||
void AttachBuffer(RequestBuffer* buffer);
|
||||
|
||||
virtual status_t Accept(RequestVisitor* visitor) = 0;
|
||||
|
||||
virtual status_t Flatten(RequestFlattener* flattener);
|
||||
virtual status_t Unflatten(RequestUnflattener* unflattener);
|
||||
|
||||
private:
|
||||
uint32 fType;
|
||||
SLList<RequestBuffer> fBuffers;
|
||||
};
|
||||
|
||||
// RequestMemberVisitor
|
||||
class RequestMemberVisitor {
|
||||
public:
|
||||
RequestMemberVisitor();
|
||||
virtual ~RequestMemberVisitor();
|
||||
|
||||
virtual void Visit(RequestMember* member, bool& data) = 0;
|
||||
virtual void Visit(RequestMember* member, int8& data) = 0;
|
||||
virtual void Visit(RequestMember* member, uint8& data) = 0;
|
||||
virtual void Visit(RequestMember* member, int16& data) = 0;
|
||||
virtual void Visit(RequestMember* member, uint16& data) = 0;
|
||||
virtual void Visit(RequestMember* member, int32& data) = 0;
|
||||
virtual void Visit(RequestMember* member, uint32& data) = 0;
|
||||
virtual void Visit(RequestMember* member, int64& data) = 0;
|
||||
virtual void Visit(RequestMember* member, uint64& data) = 0;
|
||||
virtual void Visit(RequestMember* member, Data& data) = 0;
|
||||
virtual void Visit(RequestMember* member,
|
||||
StringData& data) = 0;
|
||||
virtual void Visit(RequestMember* member,
|
||||
RequestMember& subMember) = 0;
|
||||
virtual void Visit(RequestMember* member,
|
||||
FlattenableRequestMember& subMember) = 0;
|
||||
};
|
||||
|
||||
#endif // NET_FS_REQUEST_H
|
@ -0,0 +1,32 @@
|
||||
// RequestChannel.h
|
||||
|
||||
#ifndef NET_FS_REQUEST_CHANNEL_H
|
||||
#define NET_FS_REQUEST_CHANNEL_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class Channel;
|
||||
class Request;
|
||||
|
||||
class RequestChannel {
|
||||
public:
|
||||
RequestChannel(Channel* channel);
|
||||
~RequestChannel();
|
||||
|
||||
status_t SendRequest(Request* request);
|
||||
status_t ReceiveRequest(Request** request);
|
||||
|
||||
private:
|
||||
status_t _GetRequestSize(Request* request, int32* size);
|
||||
|
||||
private:
|
||||
class ChannelWriter;
|
||||
class MemoryReader;
|
||||
struct RequestHeader;
|
||||
|
||||
Channel* fChannel;
|
||||
void* fBuffer;
|
||||
int32 fBufferSize;
|
||||
};
|
||||
|
||||
#endif // NET_FS_REQUEST_CHANNEL_H
|
@ -0,0 +1,47 @@
|
||||
// RequestConnection.h
|
||||
|
||||
#ifndef NET_FS_REQUEST_CONNECTION_H
|
||||
#define NET_FS_REQUEST_CONNECTION_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class Connection;
|
||||
class Request;
|
||||
class RequestHandler;
|
||||
|
||||
class RequestConnection {
|
||||
public:
|
||||
RequestConnection(Connection* connection,
|
||||
RequestHandler* requestHandler,
|
||||
bool ownsRequestHandler = false);
|
||||
~RequestConnection();
|
||||
|
||||
status_t Init();
|
||||
|
||||
void Close();
|
||||
|
||||
status_t SendRequest(Request* request,
|
||||
Request** reply = NULL);
|
||||
status_t SendRequest(Request* request,
|
||||
RequestHandler* replyHandler);
|
||||
private:
|
||||
class DownStreamThread;
|
||||
friend class DownStreamThread;
|
||||
|
||||
private:
|
||||
bool DownStreamChannelError(DownStreamThread* thread,
|
||||
status_t error);
|
||||
|
||||
status_t _SendRequest(Request* request, Request** reply,
|
||||
RequestHandler* replyHandler);
|
||||
|
||||
private:
|
||||
Connection* fConnection;
|
||||
RequestHandler* fRequestHandler;
|
||||
bool fOwnsRequestHandler;
|
||||
DownStreamThread* fThreads;
|
||||
int32 fThreadCount;
|
||||
vint32 fTerminationCount;
|
||||
};
|
||||
|
||||
#endif // NET_FS_REQUEST_CONNECTION_H
|
@ -0,0 +1,40 @@
|
||||
// RequestDumper.h
|
||||
|
||||
#ifndef NET_FS_REQUEST_DUMPER_H
|
||||
#define NET_FS_REQUEST_DUMPER_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "Request.h"
|
||||
|
||||
// RequestDumper
|
||||
class RequestDumper : public RequestMemberVisitor {
|
||||
public:
|
||||
RequestDumper();
|
||||
|
||||
void DumpRequest(Request* request);
|
||||
|
||||
virtual void Visit(RequestMember* member, bool& data);
|
||||
virtual void Visit(RequestMember* member, int8& data);
|
||||
virtual void Visit(RequestMember* member, uint8& data);
|
||||
virtual void Visit(RequestMember* member, int16& data);
|
||||
virtual void Visit(RequestMember* member, uint16& data);
|
||||
virtual void Visit(RequestMember* member, int32& data);
|
||||
virtual void Visit(RequestMember* member, uint32& data);
|
||||
virtual void Visit(RequestMember* member, int64& data);
|
||||
virtual void Visit(RequestMember* member, uint64& data);
|
||||
virtual void Visit(RequestMember* member, Data& data);
|
||||
virtual void Visit(RequestMember* member, StringData& data);
|
||||
virtual void Visit(RequestMember* member,
|
||||
RequestMember& subMember);
|
||||
virtual void Visit(RequestMember* member,
|
||||
FlattenableRequestMember& subMember);
|
||||
|
||||
private:
|
||||
const char* _Indentation() const;
|
||||
|
||||
private:
|
||||
int fIndentationLevel;
|
||||
};
|
||||
|
||||
#endif // NET_FS_REQUEST_DUMPER_H
|
@ -0,0 +1,18 @@
|
||||
// RequestFactory.h
|
||||
|
||||
#ifndef NET_FS_REQUEST_FACTORY_H
|
||||
#define NET_FS_REQUEST_FACTORY_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class Request;
|
||||
|
||||
class RequestFactory {
|
||||
private:
|
||||
RequestFactory();
|
||||
~RequestFactory();
|
||||
public:
|
||||
static status_t CreateRequest(uint32 type, Request** request);
|
||||
};
|
||||
|
||||
#endif // NET_FS_REQUEST_FACTORY_H
|
@ -0,0 +1,80 @@
|
||||
// RequestFlattener.h
|
||||
|
||||
#ifndef NET_FS_REQUEST_FLATTENER_H
|
||||
#define NET_FS_REQUEST_FLATTENER_H
|
||||
|
||||
#include <DataIO.h>
|
||||
|
||||
#include "Request.h"
|
||||
|
||||
// Writer
|
||||
class Writer {
|
||||
public:
|
||||
Writer();
|
||||
virtual ~Writer();
|
||||
|
||||
virtual status_t Write(const void* buffer, int32 size) = 0;
|
||||
virtual status_t Pad(int32 size);
|
||||
};
|
||||
|
||||
// DataIOWriter
|
||||
class DataIOWriter : public Writer {
|
||||
public:
|
||||
DataIOWriter(BDataIO* dataIO);
|
||||
virtual ~DataIOWriter();
|
||||
|
||||
virtual status_t Write(const void* buffer, int32 size);
|
||||
|
||||
private:
|
||||
BDataIO* fDataIO;
|
||||
};
|
||||
|
||||
// DummyWriter
|
||||
class DummyWriter : public Writer {
|
||||
public:
|
||||
DummyWriter();
|
||||
virtual ~DummyWriter();
|
||||
|
||||
virtual status_t Write(const void* buffer, int32 size);
|
||||
};
|
||||
|
||||
// RequestFlattener
|
||||
class RequestFlattener : public RequestMemberVisitor {
|
||||
public:
|
||||
RequestFlattener(Writer* writer);
|
||||
|
||||
status_t GetStatus() const;
|
||||
int32 GetBytesWritten() const;
|
||||
|
||||
virtual void Visit(RequestMember* member, bool& data);
|
||||
virtual void Visit(RequestMember* member, int8& data);
|
||||
virtual void Visit(RequestMember* member, uint8& data);
|
||||
virtual void Visit(RequestMember* member, int16& data);
|
||||
virtual void Visit(RequestMember* member, uint16& data);
|
||||
virtual void Visit(RequestMember* member, int32& data);
|
||||
virtual void Visit(RequestMember* member, uint32& data);
|
||||
virtual void Visit(RequestMember* member, int64& data);
|
||||
virtual void Visit(RequestMember* member, uint64& data);
|
||||
virtual void Visit(RequestMember* member, Data& data);
|
||||
virtual void Visit(RequestMember* member, StringData& data);
|
||||
virtual void Visit(RequestMember* member,
|
||||
RequestMember& subMember);
|
||||
virtual void Visit(RequestMember* member,
|
||||
FlattenableRequestMember& subMember);
|
||||
|
||||
status_t Write(const void* buffer, int32 size);
|
||||
status_t Align(int32 align);
|
||||
|
||||
status_t WriteBool(bool data);
|
||||
status_t WriteInt32(int32 data);
|
||||
status_t WriteData(const void* buffer, int32 size);
|
||||
status_t WriteString(const char* string);
|
||||
|
||||
private:
|
||||
Writer* fWriter;
|
||||
status_t fStatus;
|
||||
int32 fBytesWritten;
|
||||
};
|
||||
|
||||
|
||||
#endif // NET_FS_REQUEST_FLATTENER_H
|
@ -0,0 +1,28 @@
|
||||
// RequestHandler.h
|
||||
|
||||
#ifndef NET_FS_REQUEST_HANDLER_H
|
||||
#define NET_FS_REQUEST_HANDLER_H
|
||||
|
||||
#include "Requests.h"
|
||||
#include "ThreadLocal.h"
|
||||
|
||||
class RequestChannel;
|
||||
|
||||
class RequestHandler : protected RequestVisitor {
|
||||
public:
|
||||
RequestHandler();
|
||||
virtual ~RequestHandler();
|
||||
|
||||
virtual status_t HandleRequest(Request* request,
|
||||
RequestChannel* channel);
|
||||
|
||||
protected:
|
||||
virtual status_t VisitAny(Request* request);
|
||||
|
||||
RequestChannel* GetChannel() const;
|
||||
|
||||
private:
|
||||
ThreadLocal fChannels;
|
||||
};
|
||||
|
||||
#endif // NET_FS_REQUEST_HANDLER_H
|
@ -0,0 +1,123 @@
|
||||
// RequestMemberArray.h
|
||||
|
||||
#ifndef NET_FS_REQUEST_MEMBER_ARRAY_H
|
||||
#define NET_FS_REQUEST_MEMBER_ARRAY_H
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Request.h"
|
||||
#include "RequestFlattener.h"
|
||||
#include "RequestUnflattener.h"
|
||||
|
||||
template<typename Member>
|
||||
class RequestMemberArray : public FlattenableRequestMember {
|
||||
public:
|
||||
RequestMemberArray()
|
||||
: fElements(NULL),
|
||||
fSize(0),
|
||||
fCapacity(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~RequestMemberArray()
|
||||
{
|
||||
for (int32 i = 0; i < fSize; i++)
|
||||
fElements[i].~Member();
|
||||
free(fElements);
|
||||
}
|
||||
|
||||
virtual void ShowAround(RequestMemberVisitor* visitor)
|
||||
{
|
||||
visitor->Visit(this, fSize);
|
||||
for (int32 i = 0; i < fSize; i++)
|
||||
visitor->Visit(this, fElements[i]);
|
||||
}
|
||||
|
||||
virtual status_t Flatten(RequestFlattener* flattener)
|
||||
{
|
||||
if (flattener->WriteInt32(fSize) != B_OK)
|
||||
return flattener->GetStatus();
|
||||
|
||||
for (int32 i = 0; i < fSize; i++)
|
||||
flattener->Visit(this, fElements[i]);
|
||||
|
||||
return flattener->GetStatus();
|
||||
}
|
||||
|
||||
virtual status_t Unflatten(RequestUnflattener* unflattener)
|
||||
{
|
||||
if (fSize > 0) {
|
||||
for (int32 i = 0; i < fSize; i++)
|
||||
fElements[i].~Member();
|
||||
fSize = 0;
|
||||
}
|
||||
|
||||
int32 size;
|
||||
if (unflattener->ReadInt32(size) != B_OK)
|
||||
return unflattener->GetStatus();
|
||||
|
||||
status_t error = _EnsureCapacity(size);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
for (int32 i = 0; i < size; i++) {
|
||||
Member* element = new(fElements + i) Member;
|
||||
fSize = i + 1;
|
||||
unflattener->Visit(this, *element);
|
||||
}
|
||||
|
||||
return unflattener->GetStatus();
|
||||
}
|
||||
|
||||
status_t Append(const Member& element)
|
||||
{
|
||||
status_t error = _EnsureCapacity(fSize + 1);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
new(fElements + fSize) Member(element);
|
||||
fSize++;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
int32 CountElements() const
|
||||
{
|
||||
return fSize;
|
||||
}
|
||||
|
||||
Member* GetElements() const
|
||||
{
|
||||
return fElements;
|
||||
}
|
||||
|
||||
private:
|
||||
status_t _EnsureCapacity(int32 capacity)
|
||||
{
|
||||
const int32 kMinCapacity = 10;
|
||||
if (capacity < kMinCapacity)
|
||||
capacity = kMinCapacity;
|
||||
|
||||
if (capacity > fCapacity) {
|
||||
if (capacity < 2 * fCapacity)
|
||||
capacity = 2 * fCapacity;
|
||||
|
||||
Member* elements
|
||||
= (Member*)realloc(fElements, capacity * sizeof(Member));
|
||||
if (!elements)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fElements = elements;
|
||||
fCapacity = capacity;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
Member* fElements;
|
||||
int32 fSize;
|
||||
int32 fCapacity;
|
||||
};
|
||||
|
||||
#endif // NET_FS_REQUEST_MEMBER_ARRAY_H
|
@ -0,0 +1,63 @@
|
||||
// RequestUnflattener.h
|
||||
|
||||
#ifndef NET_FS_REQUEST_UNFLATTENER_H
|
||||
#define NET_FS_REQUEST_UNFLATTENER_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "Request.h"
|
||||
#include "HashString.h"
|
||||
|
||||
// Reader
|
||||
class Reader {
|
||||
public:
|
||||
Reader();
|
||||
virtual ~Reader();
|
||||
|
||||
virtual status_t Read(void* buffer, int32 size) = 0;
|
||||
virtual status_t Read(int32 size, void** buffer,
|
||||
bool* mustFree);
|
||||
virtual status_t Skip(int32 size);
|
||||
};
|
||||
|
||||
// RequestUnflattener
|
||||
class RequestUnflattener : public RequestMemberVisitor {
|
||||
public:
|
||||
RequestUnflattener(Reader* reader);
|
||||
|
||||
status_t GetStatus() const;
|
||||
int32 GetBytesRead() const;
|
||||
|
||||
virtual void Visit(RequestMember* member, bool& data);
|
||||
virtual void Visit(RequestMember* member, int8& data);
|
||||
virtual void Visit(RequestMember* member, uint8& data);
|
||||
virtual void Visit(RequestMember* member, int16& data);
|
||||
virtual void Visit(RequestMember* member, uint16& data);
|
||||
virtual void Visit(RequestMember* member, int32& data);
|
||||
virtual void Visit(RequestMember* member, uint32& data);
|
||||
virtual void Visit(RequestMember* member, int64& data);
|
||||
virtual void Visit(RequestMember* member, uint64& data);
|
||||
virtual void Visit(RequestMember* member, Data& data);
|
||||
virtual void Visit(RequestMember* member, StringData& data);
|
||||
virtual void Visit(RequestMember* member,
|
||||
RequestMember& subMember);
|
||||
virtual void Visit(RequestMember* member,
|
||||
FlattenableRequestMember& subMember);
|
||||
|
||||
status_t Read(void* buffer, int32 size);
|
||||
status_t Read(int32 size, void*& buffer, bool& mustFree);
|
||||
status_t Align(int32 align);
|
||||
|
||||
status_t ReadBool(bool& data);
|
||||
status_t ReadInt32(int32& data);
|
||||
status_t ReadData(void*& buffer, int32& size,
|
||||
bool& mustFree);
|
||||
status_t ReadString(HashString& string);
|
||||
|
||||
private:
|
||||
Reader* fReader;
|
||||
status_t fStatus;
|
||||
int32 fBytesRead;
|
||||
};
|
||||
|
||||
#endif // NET_FS_REQUEST_UNFLATTENER_H
|
1370
src/add-ons/kernel/file_systems/netfs/headers/shared/Requests.h
Normal file
1370
src/add-ons/kernel/file_systems/netfs/headers/shared/Requests.h
Normal file
File diff suppressed because it is too large
Load Diff
332
src/add-ons/kernel/file_systems/netfs/headers/shared/SLList.h
Normal file
332
src/add-ons/kernel/file_systems/netfs/headers/shared/SLList.h
Normal file
@ -0,0 +1,332 @@
|
||||
// SLList.h
|
||||
|
||||
#ifndef SL_LIST_H
|
||||
#define SL_LIST_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
namespace UserlandFSUtil {
|
||||
|
||||
// SLListLink
|
||||
template<typename Element>
|
||||
class SLListLink {
|
||||
public:
|
||||
SLListLink() : next(NULL) {}
|
||||
~SLListLink() {}
|
||||
|
||||
Element *next;
|
||||
};
|
||||
|
||||
// SLListLinkImpl
|
||||
template<typename Element>
|
||||
class SLListLinkImpl {
|
||||
private:
|
||||
typedef SLListLink<Element> Link;
|
||||
|
||||
public:
|
||||
SLListLinkImpl() : fSLListLink() {}
|
||||
~SLListLinkImpl() {}
|
||||
|
||||
Link *GetSLListLink() { return &fSLListLink; }
|
||||
const Link *GetSLListLink() const { return &fSLListLink; }
|
||||
|
||||
private:
|
||||
Link fSLListLink;
|
||||
};
|
||||
|
||||
// SLListStandardGetLink
|
||||
template<typename Element>
|
||||
class SLListStandardGetLink {
|
||||
private:
|
||||
typedef SLListLink<Element> Link;
|
||||
|
||||
public:
|
||||
inline Link *operator()(Element *element) const
|
||||
{
|
||||
return element->GetSLListLink();
|
||||
}
|
||||
|
||||
inline const Link *operator()(const Element *element) const
|
||||
{
|
||||
return element->GetSLListLink();
|
||||
}
|
||||
};
|
||||
|
||||
// for convenience
|
||||
#define SL_LIST_TEMPLATE_LIST template<typename Element, typename GetLink>
|
||||
#define SL_LIST_CLASS_NAME SLList<Element, GetLink>
|
||||
|
||||
// SLList
|
||||
template<typename Element, typename GetLink = SLListStandardGetLink<Element> >
|
||||
class SLList {
|
||||
private:
|
||||
typedef SLList<Element, GetLink> List;
|
||||
typedef SLListLink<Element> Link;
|
||||
|
||||
public:
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(List *list)
|
||||
: fList(list),
|
||||
fPrevious(NULL),
|
||||
fCurrent(NULL),
|
||||
fNext(fList->GetFirst())
|
||||
{
|
||||
}
|
||||
|
||||
Iterator(const Iterator &other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return fNext;
|
||||
}
|
||||
|
||||
Element *Next()
|
||||
{
|
||||
if (fCurrent)
|
||||
fPrevious = fCurrent;
|
||||
|
||||
fCurrent = fNext;
|
||||
|
||||
if (fNext)
|
||||
fNext = fList->GetNext(fNext);
|
||||
|
||||
return fCurrent;
|
||||
}
|
||||
|
||||
Element *Remove()
|
||||
{
|
||||
Element *element = fCurrent;
|
||||
if (fCurrent) {
|
||||
fList->_Remove(fPrevious, fCurrent);
|
||||
fCurrent = NULL;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
Iterator &operator=(const Iterator &other)
|
||||
{
|
||||
fList = other.fList;
|
||||
fPrevious = other.fPrevious;
|
||||
fCurrent = other.fCurrent;
|
||||
fNext = other.fNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
List *fList;
|
||||
Element *fPrevious;
|
||||
Element *fCurrent;
|
||||
Element *fNext;
|
||||
};
|
||||
|
||||
class ConstIterator {
|
||||
public:
|
||||
ConstIterator(const List *list)
|
||||
: fList(list),
|
||||
fNext(list->GetFirst())
|
||||
{
|
||||
}
|
||||
|
||||
ConstIterator(const ConstIterator &other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return fNext;
|
||||
}
|
||||
|
||||
Element *Next()
|
||||
{
|
||||
Element *element = fNext;
|
||||
if (fNext)
|
||||
fNext = fList->GetNext(fNext);
|
||||
return element;
|
||||
}
|
||||
|
||||
ConstIterator &operator=(const ConstIterator &other)
|
||||
{
|
||||
fList = other.fList;
|
||||
fNext = other.fNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const List *fList;
|
||||
Element *fNext;
|
||||
};
|
||||
|
||||
public:
|
||||
SLList() : fFirst(NULL), fLast(NULL) {}
|
||||
SLList(const GetLink &getLink)
|
||||
: fFirst(NULL), fLast(NULL), fGetLink(getLink) {}
|
||||
~SLList() {}
|
||||
|
||||
inline bool IsEmpty() const { return (fFirst == NULL); }
|
||||
|
||||
inline void Insert(Element *element, bool back = true);
|
||||
inline void InsertAfter(Element *previous, Element *element);
|
||||
inline void Remove(Element *element);
|
||||
// O(n)!
|
||||
|
||||
inline void MoveFrom(SL_LIST_CLASS_NAME *fromList);
|
||||
|
||||
inline void RemoveAll();
|
||||
|
||||
inline Element *GetFirst() const { return fFirst; }
|
||||
inline Element *GetLast() const { return fLast; }
|
||||
|
||||
inline Element *GetHead() const { return fFirst; }
|
||||
inline Element *GetTail() const { return fLast; }
|
||||
|
||||
inline Element *GetNext(Element *element) const;
|
||||
|
||||
inline int32 Size() const;
|
||||
// O(n)!
|
||||
|
||||
inline Iterator GetIterator() { return Iterator(this); }
|
||||
inline ConstIterator GetIterator() const { return ConstIterator(this); }
|
||||
|
||||
private:
|
||||
friend class Iterator;
|
||||
|
||||
inline void _Remove(Element *previous, Element *element);
|
||||
|
||||
private:
|
||||
Element *fFirst;
|
||||
Element *fLast;
|
||||
GetLink fGetLink;
|
||||
};
|
||||
|
||||
} // namespace UserlandFSUtil
|
||||
|
||||
using UserlandFSUtil::SLList;
|
||||
using UserlandFSUtil::SLListLink;
|
||||
using UserlandFSUtil::SLListLinkImpl;
|
||||
|
||||
|
||||
// inline methods
|
||||
|
||||
// Insert
|
||||
SL_LIST_TEMPLATE_LIST
|
||||
void
|
||||
SL_LIST_CLASS_NAME::Insert(Element *element, bool back)
|
||||
{
|
||||
InsertAfter((back ? fLast : NULL), element);
|
||||
}
|
||||
|
||||
// InsertAfter
|
||||
SL_LIST_TEMPLATE_LIST
|
||||
void
|
||||
SL_LIST_CLASS_NAME::InsertAfter(Element *previous, Element *element)
|
||||
{
|
||||
if (element) {
|
||||
Link *elLink = fGetLink(element);
|
||||
if (previous) {
|
||||
// insert after previous element
|
||||
Link *prevLink = fGetLink(previous);
|
||||
elLink->next = prevLink->next;
|
||||
prevLink->next = element;
|
||||
} else {
|
||||
// no previous element given: prepend
|
||||
elLink->next = fFirst;
|
||||
fFirst = element;
|
||||
}
|
||||
|
||||
// element may be new last element
|
||||
if (fLast == previous)
|
||||
fLast = element;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove
|
||||
SL_LIST_TEMPLATE_LIST
|
||||
void
|
||||
SL_LIST_CLASS_NAME::Remove(Element *element)
|
||||
{
|
||||
if (!element)
|
||||
return;
|
||||
|
||||
for (Iterator it = GetIterator(); it.HasNext();) {
|
||||
if (element == it.Next()) {
|
||||
it.Remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MoveFrom
|
||||
SL_LIST_TEMPLATE_LIST
|
||||
void
|
||||
SL_LIST_CLASS_NAME::MoveFrom(SL_LIST_CLASS_NAME *fromList)
|
||||
{
|
||||
if (fromList && fromList->fFirst) {
|
||||
if (fFirst) {
|
||||
fGetLink(fLast)->next = fromList->fFirst;
|
||||
fLast = fromList->fLast;
|
||||
} else {
|
||||
fFirst = fromList->fFirst;
|
||||
fLast = fromList->fLast;
|
||||
}
|
||||
fromList->fFirst = NULL;
|
||||
fromList->fLast = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveAll
|
||||
SL_LIST_TEMPLATE_LIST
|
||||
void
|
||||
SL_LIST_CLASS_NAME::RemoveAll()
|
||||
{
|
||||
Element *element = fFirst;
|
||||
while (element) {
|
||||
Link *elLink = fGetLink(element);
|
||||
element = elLink->next;
|
||||
elLink->next = NULL;
|
||||
}
|
||||
fFirst = NULL;
|
||||
fLast = NULL;
|
||||
}
|
||||
|
||||
// GetNext
|
||||
SL_LIST_TEMPLATE_LIST
|
||||
Element *
|
||||
SL_LIST_CLASS_NAME::GetNext(Element *element) const
|
||||
{
|
||||
return (element ? fGetLink(element)->next : NULL);
|
||||
}
|
||||
|
||||
// _Remove
|
||||
SL_LIST_TEMPLATE_LIST
|
||||
void
|
||||
SL_LIST_CLASS_NAME::_Remove(Element *previous, Element *element)
|
||||
{
|
||||
Link *elLink = fGetLink(element);
|
||||
if (previous)
|
||||
fGetLink(previous)->next = elLink->next;
|
||||
else
|
||||
fFirst = elLink->next;
|
||||
|
||||
if (element == fLast)
|
||||
fLast = previous;
|
||||
|
||||
elLink->next = NULL;
|
||||
}
|
||||
|
||||
// Size
|
||||
SL_LIST_TEMPLATE_LIST
|
||||
int32
|
||||
SL_LIST_CLASS_NAME::Size() const
|
||||
{
|
||||
int32 count = 0;
|
||||
for (Element* element = GetFirst(); element; element = GetNext(element))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif // SL_LIST_H
|
@ -0,0 +1,60 @@
|
||||
// ServerInfo.h
|
||||
|
||||
#ifndef NET_FS_SERVER_INFO_H
|
||||
#define NET_FS_SERVER_INFO_H
|
||||
|
||||
#include "HashString.h"
|
||||
#include "Request.h"
|
||||
#include "Vector.h"
|
||||
|
||||
// ShareInfo
|
||||
class ShareInfo : public FlattenableRequestMember {
|
||||
public:
|
||||
ShareInfo();
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
virtual void ShowAround(RequestMemberVisitor* visitor);
|
||||
|
||||
virtual status_t Flatten(RequestFlattener* flattener);
|
||||
virtual status_t Unflatten(RequestUnflattener* unflattener);
|
||||
|
||||
status_t SetShareName(const char* shareName);
|
||||
const char* GetShareName() const;
|
||||
|
||||
private:
|
||||
HashString fShareName;
|
||||
};
|
||||
|
||||
|
||||
// ServerInfo
|
||||
class ServerInfo : public FlattenableRequestMember {
|
||||
public:
|
||||
ServerInfo();
|
||||
ServerInfo(const ServerInfo& other);
|
||||
|
||||
virtual void ShowAround(RequestMemberVisitor* visitor);
|
||||
|
||||
virtual status_t Flatten(RequestFlattener* flattener);
|
||||
virtual status_t Unflatten(RequestUnflattener* unflattener);
|
||||
|
||||
status_t SetServerName(const char* serverName);
|
||||
const char* GetServerName() const;
|
||||
|
||||
status_t SetConnectionMethod(
|
||||
const char* connectionMethod);
|
||||
const char* GetConnectionMethod() const;
|
||||
|
||||
status_t AddShare(const char* shareName);
|
||||
int32 CountShares() const;
|
||||
const ShareInfo& ShareInfoAt(int32 index) const;
|
||||
|
||||
ServerInfo& operator=(const ServerInfo& other);
|
||||
|
||||
private:
|
||||
HashString fServerName;
|
||||
HashString fConnectionMethod;
|
||||
Vector<ShareInfo> fShareInfos;
|
||||
};
|
||||
|
||||
#endif // NET_FS_SERVER_INFO_H
|
@ -0,0 +1,77 @@
|
||||
// ServerNodeID.h
|
||||
|
||||
#ifndef NET_FS_SERVER_NODE_ID_H
|
||||
#define NET_FS_SERVER_NODE_ID_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "Request.h"
|
||||
|
||||
// NodeID
|
||||
struct NodeID {
|
||||
NodeID()
|
||||
: volumeID(-1),
|
||||
nodeID(-1)
|
||||
{
|
||||
}
|
||||
|
||||
NodeID(dev_t volumeID, ino_t nodeID)
|
||||
: volumeID(volumeID),
|
||||
nodeID(nodeID)
|
||||
{
|
||||
}
|
||||
|
||||
NodeID(const NodeID& other)
|
||||
: volumeID(other.volumeID),
|
||||
nodeID(other.nodeID)
|
||||
{
|
||||
}
|
||||
|
||||
uint32 GetHashCode() const
|
||||
{
|
||||
uint64 v = (uint64)nodeID;
|
||||
return (uint32)(v >> 32) ^ (uint32)v ^ (uint32)volumeID;
|
||||
}
|
||||
|
||||
NodeID& operator=(const NodeID& other)
|
||||
{
|
||||
volumeID = other.volumeID;
|
||||
nodeID = other.nodeID;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const NodeID& other) const
|
||||
{
|
||||
return (volumeID == other.volumeID && nodeID == other.nodeID);
|
||||
}
|
||||
|
||||
bool operator!=(const NodeID& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
dev_t volumeID;
|
||||
ino_t nodeID;
|
||||
};
|
||||
|
||||
// ServerNodeID
|
||||
struct ServerNodeID : RequestMember, NodeID {
|
||||
ServerNodeID();
|
||||
ServerNodeID(dev_t volumeID, ino_t nodeID);
|
||||
virtual ~ServerNodeID();
|
||||
|
||||
virtual void ShowAround(RequestMemberVisitor* visitor);
|
||||
|
||||
inline ServerNodeID& operator=(const NodeID& other);
|
||||
};
|
||||
|
||||
// =
|
||||
inline
|
||||
ServerNodeID&
|
||||
ServerNodeID::operator=(const NodeID& other)
|
||||
{
|
||||
NodeID::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif // NET_FS_SERVER_NODE_ID_H
|
@ -0,0 +1,53 @@
|
||||
// TaskManager.h
|
||||
|
||||
#ifndef NET_FS_TASK_MANAGER_H
|
||||
#define NET_FS_TASK_MANAGER_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include <HashString.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
// Task
|
||||
class Task : public DoublyLinkedListLinkImpl<Task> {
|
||||
public:
|
||||
Task(const char* name);
|
||||
virtual ~Task();
|
||||
|
||||
status_t Run();
|
||||
void Terminate();
|
||||
|
||||
bool IsDone() const;
|
||||
|
||||
virtual status_t Execute() = 0;
|
||||
virtual void Stop();
|
||||
|
||||
protected:
|
||||
void SetDone(bool done);
|
||||
|
||||
private:
|
||||
static int32 _ThreadEntry(void* data);
|
||||
int32 _Thread();
|
||||
|
||||
private:
|
||||
HashString fName;
|
||||
thread_id fThread;
|
||||
bool fTerminating;
|
||||
bool fDone;
|
||||
};
|
||||
|
||||
// TaskManager
|
||||
class TaskManager {
|
||||
public:
|
||||
TaskManager();
|
||||
~TaskManager();
|
||||
|
||||
status_t RunTask(Task* task);
|
||||
void RemoveDoneTasks();
|
||||
void TerminateAllTasks();
|
||||
|
||||
private:
|
||||
DoublyLinkedList<Task> fTasks;
|
||||
};
|
||||
|
||||
#endif // NET_FS_TASK_MANAGER_H
|
@ -0,0 +1,58 @@
|
||||
// ThreadLocal.h
|
||||
|
||||
#ifndef THREAD_LOCAL_H
|
||||
#define THREAD_LOCAL_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
// ThreadLocalFreeHandler
|
||||
class ThreadLocalFreeHandler {
|
||||
public:
|
||||
ThreadLocalFreeHandler();
|
||||
virtual ~ThreadLocalFreeHandler();
|
||||
|
||||
virtual void Free(void* data) = 0;
|
||||
};
|
||||
|
||||
// ThreadLocal
|
||||
class ThreadLocal {
|
||||
public:
|
||||
ThreadLocal(
|
||||
ThreadLocalFreeHandler* freeHandler = NULL);
|
||||
~ThreadLocal();
|
||||
|
||||
status_t Set(void* data);
|
||||
void Unset();
|
||||
void* Get() const;
|
||||
|
||||
private:
|
||||
struct ThreadLocalMap;
|
||||
|
||||
ThreadLocalMap* fMap;
|
||||
ThreadLocalFreeHandler* fFreeHandler;
|
||||
};
|
||||
|
||||
// ThreadLocalUnsetter
|
||||
class ThreadLocalUnsetter {
|
||||
public:
|
||||
ThreadLocalUnsetter(ThreadLocal* threadLocal)
|
||||
: fThreadLocal(threadLocal)
|
||||
{
|
||||
}
|
||||
|
||||
ThreadLocalUnsetter(ThreadLocal& threadLocal)
|
||||
: fThreadLocal(&threadLocal)
|
||||
{
|
||||
}
|
||||
|
||||
~ThreadLocalUnsetter()
|
||||
{
|
||||
if (fThreadLocal)
|
||||
fThreadLocal->Unset();
|
||||
}
|
||||
|
||||
private:
|
||||
ThreadLocal* fThreadLocal;
|
||||
};
|
||||
|
||||
#endif // THREAD_LOCAL_H
|
42
src/add-ons/kernel/file_systems/netfs/headers/shared/Utils.h
Normal file
42
src/add-ons/kernel/file_systems/netfs/headers/shared/Utils.h
Normal file
@ -0,0 +1,42 @@
|
||||
// Utils.h
|
||||
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#ifdef HAIKU_TARGET_PLATFORM_BEOS
|
||||
# include <socket.h>
|
||||
#else
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "Compatibility.h"
|
||||
|
||||
template<typename T> T max(const T& a, const T& b) { return (a > b ? a : b); }
|
||||
template<typename T> T min(const T& a, const T& b) { return (a < b ? a : b); }
|
||||
|
||||
// safe_closesocket
|
||||
/*! There seems to be race condition on a net_server system, if two threads
|
||||
try to close the same socket at the same time. This is work-around. The
|
||||
variable which stores the socket ID must be a vint32.
|
||||
*/
|
||||
static inline
|
||||
void
|
||||
safe_closesocket(vint32& socketVar)
|
||||
{
|
||||
int32 socket = atomic_or(&socketVar, -1);
|
||||
#ifdef __HAIKU__
|
||||
close(socket);
|
||||
#else
|
||||
if (socket >= 0) {
|
||||
# ifndef HAIKU_TARGET_PLATFORM_BEOS
|
||||
shutdown(socket, SHUTDOWN_BOTH);
|
||||
# endif
|
||||
closesocket(socket);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // UTILS_H
|
42
src/add-ons/kernel/file_systems/netfs/netfs-server
Normal file
42
src/add-ons/kernel/file_systems/netfs/netfs-server
Normal file
@ -0,0 +1,42 @@
|
||||
# netfs server settings
|
||||
#
|
||||
# Lives in /boot/home/config/settings/kernel/drivers/.
|
||||
|
||||
# users
|
||||
user bonefish {
|
||||
password password
|
||||
}
|
||||
|
||||
user anonymous
|
||||
|
||||
# shares
|
||||
share ttttt {
|
||||
path /boot/home/Desktop/ttttt
|
||||
user bonefish {
|
||||
permissions mount query read write
|
||||
}
|
||||
}
|
||||
|
||||
share sub-ttttt {
|
||||
path /boot/home/Desktop/ttttt/rmessage
|
||||
user bonefish {
|
||||
permissions mount query read write
|
||||
}
|
||||
}
|
||||
|
||||
#share home {
|
||||
# path /boot/home
|
||||
# user bonefish {
|
||||
# permissions mount query read write
|
||||
# }
|
||||
#}
|
||||
|
||||
#share tmp {
|
||||
# path /boot/home/tmp
|
||||
# user bonefish {
|
||||
# permissions mount query read write
|
||||
# }
|
||||
# user anonymous {
|
||||
# permissions mount query read
|
||||
# }
|
||||
#}
|
16
src/add-ons/kernel/file_systems/netfs/netfs_config/Jamfile
Normal file
16
src/add-ons/kernel/file_systems/netfs/netfs_config/Jamfile
Normal file
@ -0,0 +1,16 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel file_systems netfs netfs_config ;
|
||||
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) headers fs ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) headers shared ] ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) shared ] ;
|
||||
|
||||
DEFINES += USER=1 ;
|
||||
DEFINES += DEBUG_APP="\\\"server_config\\\"" ;
|
||||
|
||||
Application netfs_config
|
||||
: DebugSupport.cpp
|
||||
|
||||
netfs_config.cpp
|
||||
: be
|
||||
;
|
@ -0,0 +1,109 @@
|
||||
// netfs_config.cpp
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "netfs_ioctl.h"
|
||||
|
||||
// usage
|
||||
static const char* kUsage =
|
||||
"Usage: netfs_config -h | --help\n"
|
||||
" netfs_config <mount point> -a <server name>\n"
|
||||
" netfs_config <mount point> -r <server name>\n"
|
||||
"options:\n"
|
||||
" -a - adds the supplied server\n"
|
||||
" -h, --help - print this text\n"
|
||||
" -r - removes the supplied server\n"
|
||||
;
|
||||
|
||||
// print_usage
|
||||
static
|
||||
void
|
||||
print_usage(bool error)
|
||||
{
|
||||
fprintf((error ? stderr : stdout), kUsage);
|
||||
}
|
||||
|
||||
// add_server
|
||||
static
|
||||
status_t
|
||||
add_server(int fd, const char* serverName)
|
||||
{
|
||||
netfs_ioctl_add_server params;
|
||||
if (strlen(serverName) >= sizeof(params.serverName))
|
||||
return B_BAD_VALUE;
|
||||
strcpy(params.serverName, serverName);
|
||||
if (ioctl(fd, NET_FS_IOCTL_ADD_SERVER, ¶ms) < 0)
|
||||
return errno;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// remove_server
|
||||
static
|
||||
status_t
|
||||
remove_server(int fd, const char* serverName)
|
||||
{
|
||||
netfs_ioctl_remove_server params;
|
||||
if (strlen(serverName) >= sizeof(params.serverName))
|
||||
return B_BAD_VALUE;
|
||||
strcpy(params.serverName, serverName);
|
||||
if (ioctl(fd, NET_FS_IOCTL_REMOVE_SERVER, ¶ms) < 0)
|
||||
return errno;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// main
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
// parse the arguments
|
||||
if (argc < 2) {
|
||||
print_usage(true);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) {
|
||||
print_usage(false);
|
||||
return 0;
|
||||
}
|
||||
// add or remove
|
||||
if (argc != 4) {
|
||||
print_usage(true);
|
||||
return 1;
|
||||
}
|
||||
const char* mountPoint = argv[1];
|
||||
bool add = false;
|
||||
if (strcmp(argv[2], "-a") == 0) {
|
||||
add = true;
|
||||
} else if (strcmp(argv[2], "-r") == 0) {
|
||||
add = false;
|
||||
} else {
|
||||
print_usage(true);
|
||||
return 1;
|
||||
}
|
||||
const char* serverName = argv[3];
|
||||
// open the mount point
|
||||
int fd = open(mountPoint, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Opening `%s' failed: %s\n", mountPoint,
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
// do the ioctl
|
||||
status_t error = B_OK;
|
||||
if (add)
|
||||
error = add_server(fd, serverName);
|
||||
else
|
||||
error = remove_server(fd, serverName);
|
||||
if (error != B_OK)
|
||||
fprintf(stderr, "Operation failed: %s\n", strerror(error));
|
||||
// clean up
|
||||
close(fd);
|
||||
return (error == B_OK ? 0 : 1);
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel file_systems netfs netfs_server_prefs ;
|
||||
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) headers server ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) headers shared ] ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) shared ] ;
|
||||
|
||||
DEFINES += USER=1 ;
|
||||
DEFINES += DEBUG_APP="\\\"NetFSServerPrefs\\\"" ;
|
||||
|
||||
Application NetFSServerPrefs
|
||||
: DebugSupport.cpp
|
||||
|
||||
NetFSServerRosterDefs.cpp
|
||||
|
||||
NetFSServerPrefs.cpp
|
||||
NetFSServerRoster.cpp
|
||||
: be
|
||||
;
|
@ -0,0 +1,488 @@
|
||||
// NetFSServerPrefs.cpp
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Application.h>
|
||||
#include <Message.h>
|
||||
|
||||
#include "NetFSServerRoster.h"
|
||||
#include "Permissions.h"
|
||||
|
||||
// simplified permissions
|
||||
static const uint32 kMountPermission = MOUNT_SHARE_PERMISSION;
|
||||
static const uint32 kQueryPermission = QUERY_SHARE_PERMISSION;
|
||||
static const uint32 kReadPermission
|
||||
= READ_PERMISSION | READ_DIR_PERMISSION | RESOLVE_DIR_ENTRY_PERMISSION;
|
||||
static const uint32 kWritePermission
|
||||
= WRITE_PERMISSION | WRITE_DIR_PERMISSION;
|
||||
|
||||
// usage
|
||||
static const char* kUsage =
|
||||
"Usage: NetFSServerPrefs -h | --help\n"
|
||||
" NetFSServerPrefs <command>\n"
|
||||
"options:\n"
|
||||
" -h, --help - print this text\n"
|
||||
"\n"
|
||||
"commands:\n"
|
||||
" launch\n"
|
||||
" launches the server\n"
|
||||
" terminate\n"
|
||||
" terminates the server\n"
|
||||
" save\n"
|
||||
" saves the server settings\n"
|
||||
" l, list\n"
|
||||
" list all users and all shares\n"
|
||||
" add share <name> <path>\n"
|
||||
" add a new share with the name <name> and path <path>\n"
|
||||
" remove share <name>\n"
|
||||
" remove the share named <name>\n"
|
||||
" add user <name> [ <password> ]\n"
|
||||
" add a new user with the name <name> and, if supplied, \n"
|
||||
" password <password>\n"
|
||||
" remove user <name>\n"
|
||||
" remove the user named <name>\n"
|
||||
" permissions <user> <share> [ m ] [ r ] [ w ] [ q ]\n"
|
||||
" set the permissions of user <user> for share <share> to m(ount),\n"
|
||||
" r(ead), w(rite), and/or q(uery).\n"
|
||||
;
|
||||
|
||||
// print_usage
|
||||
static
|
||||
void
|
||||
print_usage(bool error)
|
||||
{
|
||||
fprintf((error ? stderr : stdout), kUsage);
|
||||
}
|
||||
|
||||
// print_usage_and_exit
|
||||
static
|
||||
void
|
||||
print_usage_and_exit(bool error)
|
||||
{
|
||||
print_usage(error);
|
||||
exit(error ? 1 : 0);
|
||||
}
|
||||
|
||||
// get_permissions_string
|
||||
static
|
||||
void
|
||||
get_permissions_string(uint32 permissions, char* str)
|
||||
{
|
||||
str[0] = (permissions & kMountPermission ? 'm' : '-');
|
||||
str[1] = (permissions & kReadPermission ? 'r' : '-');
|
||||
str[2] = (permissions & kWritePermission ? 'w' : '-');
|
||||
str[3] = (permissions & kQueryPermission ? 'q' : '-');
|
||||
str[4] = '\0';
|
||||
}
|
||||
|
||||
// get_permissions
|
||||
static
|
||||
bool
|
||||
get_permissions(const char* str, uint32* permissions)
|
||||
{
|
||||
*permissions = 0;
|
||||
|
||||
if (!str)
|
||||
return true;
|
||||
|
||||
while (*str) {
|
||||
switch (*str) {
|
||||
case 'm':
|
||||
*permissions |= kMountPermission;
|
||||
break;
|
||||
case 'r':
|
||||
*permissions |= kReadPermission;
|
||||
break;
|
||||
case 'w':
|
||||
*permissions |= kWritePermission;
|
||||
break;
|
||||
case 'q':
|
||||
*permissions |= kQueryPermission;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// assert_server_running
|
||||
static
|
||||
void
|
||||
assert_server_running()
|
||||
{
|
||||
// check, if the server is running
|
||||
NetFSServerRoster roster;
|
||||
if (!roster.IsServerRunning()) {
|
||||
fprintf(stderr, "Server is not running.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// list
|
||||
static
|
||||
void
|
||||
list()
|
||||
{
|
||||
assert_server_running();
|
||||
|
||||
NetFSServerRoster roster;
|
||||
|
||||
// get the users
|
||||
BMessage users;
|
||||
status_t error = roster.GetUsers(&users);
|
||||
if (error == B_OK) {
|
||||
// list the users
|
||||
printf("users\n");
|
||||
printf("-----\n");
|
||||
const char* user;
|
||||
for (int32 i = 0; users.FindString("users", i, &user) == B_OK; i++)
|
||||
printf("%s\n", user);
|
||||
printf("\n");
|
||||
} else
|
||||
fprintf(stderr, "Failed to get users: %s\n", strerror(error));
|
||||
|
||||
// get the shares
|
||||
BMessage shares;
|
||||
error = roster.GetShares(&shares);
|
||||
if (error == B_OK) {
|
||||
// list the shares
|
||||
printf("shares\n");
|
||||
printf("------\n");
|
||||
const char* share;
|
||||
for (int32 i = 0; shares.FindString("shares", i, &share) == B_OK; i++) {
|
||||
// get path
|
||||
const char* path;
|
||||
if (shares.FindString("paths", i, &path) != B_OK)
|
||||
path = "<invalid path>\n";
|
||||
|
||||
// get share users
|
||||
BMessage shareUsers;
|
||||
roster.GetShareUsers(share, &shareUsers);
|
||||
|
||||
// get statistics
|
||||
BMessage statistics;
|
||||
roster.GetShareStatistics(share, &statistics);
|
||||
|
||||
printf("%s:\n", share);
|
||||
printf(" path: %s\n", path);
|
||||
|
||||
// print permitted users
|
||||
printf(" mountable by: ");
|
||||
const char* user;
|
||||
for (int32 k = 0;
|
||||
shareUsers.FindString("users", k, &user) == B_OK;
|
||||
k++) {
|
||||
if (k > 0)
|
||||
printf(", ");
|
||||
printf("%s", user);
|
||||
|
||||
// print permissions
|
||||
uint32 permissions = 0;
|
||||
roster.GetUserPermissions(share, user, &permissions);
|
||||
char permissionsString[8];
|
||||
get_permissions_string(permissions, permissionsString);
|
||||
printf(" (%s)", permissionsString);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// print current users
|
||||
printf(" mounted by: ");
|
||||
for (int32 k = 0;
|
||||
statistics.FindString("mounted by", k, &user) == B_OK;
|
||||
k++) {
|
||||
if (k > 0)
|
||||
printf(", ");
|
||||
printf("%s", user);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
} else
|
||||
fprintf(stderr, "Failed to get users: %s\n", strerror(error));
|
||||
}
|
||||
|
||||
// add_share
|
||||
static
|
||||
void
|
||||
add_share(const char* name, const char* path)
|
||||
{
|
||||
assert_server_running();
|
||||
|
||||
NetFSServerRoster roster;
|
||||
|
||||
// check whether a share with the given name already exists
|
||||
BMessage statistics;
|
||||
if (roster.GetShareStatistics(name, &statistics) == B_OK) {
|
||||
fprintf(stderr, "A share `%s' does already exist.\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// add the share
|
||||
status_t error = roster.AddShare(name, path);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to add share: %s\n", strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// remove_share
|
||||
static
|
||||
void
|
||||
remove_share(const char* name)
|
||||
{
|
||||
assert_server_running();
|
||||
|
||||
NetFSServerRoster roster;
|
||||
|
||||
// check whether a share with the given name exists
|
||||
BMessage statistics;
|
||||
if (roster.GetShareStatistics(name, &statistics) != B_OK) {
|
||||
fprintf(stderr, "A share `%s' does not exist.\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// remove the share
|
||||
status_t error = roster.RemoveShare(name);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to remove share: %s\n", strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// add_user
|
||||
static
|
||||
void
|
||||
add_user(const char* name, const char* password)
|
||||
{
|
||||
assert_server_running();
|
||||
|
||||
NetFSServerRoster roster;
|
||||
|
||||
// check whether a user with the given name already exists
|
||||
BMessage statistics;
|
||||
if (roster.GetUserStatistics(name, &statistics) == B_OK) {
|
||||
fprintf(stderr, "A user `%s' does already exist.\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// add the user
|
||||
status_t error = roster.AddUser(name, password);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to add user: %s\n", strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// remove_user
|
||||
static
|
||||
void
|
||||
remove_user(const char* name)
|
||||
{
|
||||
assert_server_running();
|
||||
|
||||
NetFSServerRoster roster;
|
||||
|
||||
// check whether a user with the given name exists
|
||||
BMessage statistics;
|
||||
if (roster.GetUserStatistics(name, &statistics) != B_OK) {
|
||||
fprintf(stderr, "A user `%s' does not exist.\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// remove the user
|
||||
status_t error = roster.RemoveUser(name);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to remove user: %s\n", strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// set_user_permissions
|
||||
static
|
||||
void
|
||||
set_user_permissions(const char* user, const char* share, uint32 permissions)
|
||||
{
|
||||
assert_server_running();
|
||||
|
||||
NetFSServerRoster roster;
|
||||
|
||||
// check whether a user with the given name exists
|
||||
BMessage statistics;
|
||||
if (roster.GetUserStatistics(user, &statistics) != B_OK) {
|
||||
fprintf(stderr, "A user `%s' does not exist.\n", user);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// check whether a share with the given name exists
|
||||
if (roster.GetShareStatistics(share, &statistics) != B_OK) {
|
||||
fprintf(stderr, "A share `%s' does not exist.\n", share);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// set the permissions
|
||||
status_t error = roster.SetUserPermissions(share, user, permissions);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to set permissions: %s\n", strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// launch_server
|
||||
static
|
||||
void
|
||||
launch_server()
|
||||
{
|
||||
NetFSServerRoster roster;
|
||||
|
||||
if (roster.IsServerRunning()) {
|
||||
fprintf(stderr, "Server is already running.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
status_t error = roster.LaunchServer();
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to launch server: %s\n", strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// terminate_server
|
||||
static
|
||||
void
|
||||
terminate_server()
|
||||
{
|
||||
assert_server_running();
|
||||
|
||||
NetFSServerRoster roster;
|
||||
|
||||
status_t error = roster.TerminateServer();
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to terminate server: %s\n", strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// save_server_setttings
|
||||
static
|
||||
void
|
||||
save_server_setttings()
|
||||
{
|
||||
assert_server_running();
|
||||
|
||||
NetFSServerRoster roster;
|
||||
|
||||
status_t error = roster.SaveServerSettings();
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to save settings: %s\n", strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// next_arg
|
||||
static
|
||||
const char*
|
||||
next_arg(int argc, char** argv, int& argi, bool dontFail = false)
|
||||
{
|
||||
if (argi >= argc) {
|
||||
if (dontFail)
|
||||
return NULL;
|
||||
print_usage_and_exit(true);
|
||||
}
|
||||
|
||||
return argv[argi++];
|
||||
}
|
||||
|
||||
// no_more_args
|
||||
static
|
||||
void
|
||||
no_more_args(int argc, int argi)
|
||||
{
|
||||
if (argi < argc)
|
||||
print_usage_and_exit(true);
|
||||
}
|
||||
|
||||
// main
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
BApplication app("application/x-vnd.yellowbites.NetFSServerPrefs");
|
||||
|
||||
// parse first argument
|
||||
int argi = 1;
|
||||
const char* arg = next_arg(argc, argv, argi);
|
||||
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
|
||||
print_usage_and_exit(false);
|
||||
|
||||
if (strcmp(arg, "launch") == 0) {
|
||||
// launch
|
||||
no_more_args(argc, argi);
|
||||
launch_server();
|
||||
} else if (strcmp(arg, "terminate") == 0) {
|
||||
// terminate
|
||||
no_more_args(argc, argi);
|
||||
terminate_server();
|
||||
} else if (strcmp(arg, "save") == 0) {
|
||||
// save
|
||||
no_more_args(argc, argi);
|
||||
save_server_setttings();
|
||||
} else if (strcmp(arg, "l") == 0 || strcmp(arg, "list") == 0) {
|
||||
// list
|
||||
no_more_args(argc, argi);
|
||||
list();
|
||||
} else if (strcmp(arg, "add") == 0) {
|
||||
// add
|
||||
arg = next_arg(argc, argv, argi);
|
||||
if (strcmp(arg, "share") == 0) {
|
||||
// share
|
||||
const char* name = next_arg(argc, argv, argi);
|
||||
const char* path = next_arg(argc, argv, argi);
|
||||
no_more_args(argc, argi);
|
||||
add_share(name, path);
|
||||
} else if (strcmp(arg, "user") == 0) {
|
||||
// user
|
||||
const char* name = next_arg(argc, argv, argi);
|
||||
const char* password = next_arg(argc, argv, argi, true);
|
||||
no_more_args(argc, argi);
|
||||
add_user(name, password);
|
||||
} else
|
||||
print_usage_and_exit(true);
|
||||
} else if (strcmp(arg, "remove") == 0) {
|
||||
// remove
|
||||
arg = next_arg(argc, argv, argi);
|
||||
if (strcmp(arg, "share") == 0) {
|
||||
// share
|
||||
const char* name = next_arg(argc, argv, argi);
|
||||
no_more_args(argc, argi);
|
||||
remove_share(name);
|
||||
} else if (strcmp(arg, "user") == 0) {
|
||||
// user
|
||||
const char* name = next_arg(argc, argv, argi);
|
||||
no_more_args(argc, argi);
|
||||
remove_user(name);
|
||||
} else
|
||||
print_usage_and_exit(true);
|
||||
} else if (strcmp(arg, "permissions") == 0) {
|
||||
// permissions
|
||||
const char* user = next_arg(argc, argv, argi);
|
||||
const char* share = next_arg(argc, argv, argi);
|
||||
uint32 permissions = 0;
|
||||
while (argi < argc) {
|
||||
uint32 perms = 0;
|
||||
arg = next_arg(argc, argv, argi);
|
||||
if (!get_permissions(arg, &perms))
|
||||
print_usage_and_exit(true);
|
||||
permissions |= perms;
|
||||
}
|
||||
set_user_permissions(user, share, permissions);
|
||||
} else {
|
||||
print_usage_and_exit(true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,409 @@
|
||||
// NetFSServerRoster.cpp
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <Message.h>
|
||||
#include <OS.h>
|
||||
#include <Roster.h>
|
||||
|
||||
#include "NetFSServerRoster.h"
|
||||
#include "NetFSServerRosterDefs.h"
|
||||
|
||||
// constructor
|
||||
NetFSServerRoster::NetFSServerRoster()
|
||||
: fServerMessenger()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
NetFSServerRoster::~NetFSServerRoster()
|
||||
{
|
||||
}
|
||||
|
||||
// IsServerRunning
|
||||
bool
|
||||
NetFSServerRoster::IsServerRunning()
|
||||
{
|
||||
return (_InitMessenger() == B_OK);
|
||||
}
|
||||
|
||||
// LaunchServer
|
||||
status_t
|
||||
NetFSServerRoster::LaunchServer()
|
||||
{
|
||||
status_t error = BRoster().Launch(kNetFSServerSignature);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
return _InitMessenger();
|
||||
}
|
||||
|
||||
// TerminateServer
|
||||
status_t
|
||||
NetFSServerRoster::TerminateServer(bool force, bigtime_t timeout)
|
||||
{
|
||||
// get the server team
|
||||
team_id team = BRoster().TeamFor(kNetFSServerSignature);
|
||||
if (team < 0)
|
||||
return team;
|
||||
|
||||
// create a semaphore an transfer its ownership to the server team
|
||||
sem_id deathSem = create_sem(0, "netfs server death");
|
||||
set_sem_owner(deathSem, team);
|
||||
|
||||
status_t error = B_OK;
|
||||
if (force) {
|
||||
// terminate it the hard way
|
||||
kill_team(team);
|
||||
|
||||
// wait the specified time
|
||||
error = acquire_sem_etc(deathSem, 1, B_RELATIVE_TIMEOUT, timeout);
|
||||
} else {
|
||||
// get a messenger
|
||||
BMessenger messenger(NULL, team);
|
||||
if (messenger.IsValid()) {
|
||||
// tell the server to quit
|
||||
messenger.SendMessage(B_QUIT_REQUESTED);
|
||||
|
||||
// wait the specified time
|
||||
error = acquire_sem_etc(deathSem, 1, B_RELATIVE_TIMEOUT, timeout);
|
||||
} else
|
||||
error = B_ERROR;
|
||||
}
|
||||
|
||||
delete_sem(deathSem);
|
||||
|
||||
// if the semaphore is gone, the server is gone, as well
|
||||
return (error == B_BAD_SEM_ID ? B_OK : B_ERROR);
|
||||
}
|
||||
|
||||
// SaveServerSettings
|
||||
status_t
|
||||
NetFSServerRoster::SaveServerSettings()
|
||||
{
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_SAVE_SETTINGS);
|
||||
|
||||
// send the request
|
||||
return _SendRequest(&request);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// AddUser
|
||||
status_t
|
||||
NetFSServerRoster::AddUser(const char* user, const char* password)
|
||||
{
|
||||
// check parameters
|
||||
if (!user || strlen(user) < 1)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_ADD_USER);
|
||||
if (request.AddString("user", user) != B_OK
|
||||
|| (password && request.AddString("password", password) != B_OK)) {
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// send the request
|
||||
return _SendRequest(&request);
|
||||
}
|
||||
|
||||
// RemoveUser
|
||||
status_t
|
||||
NetFSServerRoster::RemoveUser(const char* user)
|
||||
{
|
||||
// check parameters
|
||||
if (!user || strlen(user) < 1)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_REMOVE_USER);
|
||||
if (request.AddString("user", user) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// send the request
|
||||
return _SendRequest(&request);
|
||||
}
|
||||
|
||||
// GetUsers
|
||||
status_t
|
||||
NetFSServerRoster::GetUsers(BMessage* users)
|
||||
{
|
||||
// check parameters
|
||||
if (!users)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_GET_USERS);
|
||||
|
||||
// send the request
|
||||
BMessage reply;
|
||||
status_t error = _SendRequest(&request, &reply);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// get the result
|
||||
if (reply.FindMessage("users", users) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// GetUserStatistics
|
||||
status_t
|
||||
NetFSServerRoster::GetUserStatistics(const char* user, BMessage* statistics)
|
||||
{
|
||||
// check parameters
|
||||
if (!user || strlen(user) < 1 || !statistics)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_GET_USER_STATISTICS);
|
||||
if (request.AddString("user", user) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// send the request
|
||||
BMessage reply;
|
||||
status_t error = _SendRequest(&request, &reply);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// get the result
|
||||
if (reply.FindMessage("statistics", statistics) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// AddShare
|
||||
status_t
|
||||
NetFSServerRoster::AddShare(const char* share, const char* path)
|
||||
{
|
||||
// check parameters
|
||||
if (!share || strlen(share) < 1 || !path || strlen(path) < 1)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_ADD_SHARE);
|
||||
if (request.AddString("share", share) != B_OK
|
||||
|| request.AddString("path", path) != B_OK) {
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// send the request
|
||||
return _SendRequest(&request);
|
||||
}
|
||||
|
||||
// RemoveShare
|
||||
status_t
|
||||
NetFSServerRoster::RemoveShare(const char* share)
|
||||
{
|
||||
// check parameters
|
||||
if (!share || strlen(share) < 1)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_REMOVE_SHARE);
|
||||
if (request.AddString("share", share) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// send the request
|
||||
return _SendRequest(&request);
|
||||
}
|
||||
|
||||
// GetShares
|
||||
status_t
|
||||
NetFSServerRoster::GetShares(BMessage* shares)
|
||||
{
|
||||
// check parameters
|
||||
if (!shares)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_GET_SHARES);
|
||||
|
||||
// send the request
|
||||
BMessage reply;
|
||||
status_t error = _SendRequest(&request, &reply);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// get the result
|
||||
if (reply.FindMessage("shares", shares) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// GetShareUsers
|
||||
status_t
|
||||
NetFSServerRoster::GetShareUsers(const char* share, BMessage* users)
|
||||
{
|
||||
// check parameters
|
||||
if (!share || strlen(share) < 1 || !users)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_GET_SHARE_USERS);
|
||||
if (request.AddString("share", share) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// send the request
|
||||
BMessage reply;
|
||||
status_t error = _SendRequest(&request, &reply);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// get the result
|
||||
if (reply.FindMessage("users", users) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// GetShareStatistics
|
||||
status_t
|
||||
NetFSServerRoster::GetShareStatistics(const char* share, BMessage* statistics)
|
||||
{
|
||||
// check parameters
|
||||
if (!share || strlen(share) < 1 || !statistics)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_GET_SHARE_STATISTICS);
|
||||
if (request.AddString("share", share) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// send the request
|
||||
BMessage reply;
|
||||
status_t error = _SendRequest(&request, &reply);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// get the result
|
||||
if (reply.FindMessage("statistics", statistics) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// SetUserPermissions
|
||||
status_t
|
||||
NetFSServerRoster::SetUserPermissions(const char* share, const char* user,
|
||||
uint32 permissions)
|
||||
{
|
||||
// check parameters
|
||||
if (!share || strlen(share) < 1 || !user || strlen(user) < 1)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_SET_USER_PERMISSIONS);
|
||||
if (request.AddString("share", share) != B_OK
|
||||
|| request.AddString("user", user) != B_OK
|
||||
|| request.AddInt32("permissions", (int32)permissions)) {
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// send the request
|
||||
return _SendRequest(&request);
|
||||
}
|
||||
|
||||
// GetUserPermissions
|
||||
status_t
|
||||
NetFSServerRoster::GetUserPermissions(const char* share, const char* user,
|
||||
uint32* permissions)
|
||||
{
|
||||
// check parameters
|
||||
if (!share || strlen(share) < 1 || !user || strlen(user) < 1
|
||||
|| !permissions) {
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// prepare the request
|
||||
BMessage request(NETFS_REQUEST_GET_USER_PERMISSIONS);
|
||||
if (request.AddString("share", share) != B_OK
|
||||
|| request.AddString("user", user) != B_OK) {
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// send the request
|
||||
BMessage reply;
|
||||
status_t error = _SendRequest(&request, &reply);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// get the result
|
||||
if (reply.FindInt32("permissions", (int32*)permissions) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _InitMessenger
|
||||
status_t
|
||||
NetFSServerRoster::_InitMessenger()
|
||||
{
|
||||
// do we already have a valid messenger?
|
||||
if (fServerMessenger.IsValid())
|
||||
return B_OK;
|
||||
|
||||
// get a messenger to the server application
|
||||
BMessenger appMessenger(kNetFSServerSignature);
|
||||
if (!appMessenger.IsValid())
|
||||
return B_NO_INIT;
|
||||
|
||||
// send a request to get the real messenger
|
||||
BMessage request(NETFS_REQUEST_GET_MESSENGER);
|
||||
BMessage reply;
|
||||
if (appMessenger.SendMessage(&request, &reply) != B_OK)
|
||||
return B_NO_INIT;
|
||||
|
||||
// check the result
|
||||
status_t error;
|
||||
if (reply.FindInt32("error", &error) != B_OK)
|
||||
return B_ERROR;
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// get the messenger
|
||||
if (reply.FindMessenger("messenger", &fServerMessenger) != B_OK)
|
||||
return B_NO_INIT;
|
||||
|
||||
return (fServerMessenger.IsValid() ? B_OK : B_NO_INIT);
|
||||
}
|
||||
|
||||
// _SendRequest
|
||||
status_t
|
||||
NetFSServerRoster::_SendRequest(BMessage* request, BMessage* reply)
|
||||
{
|
||||
// if no reply data are expected, create a reply message on the stack
|
||||
BMessage stackReply;
|
||||
if (!reply)
|
||||
reply = &stackReply;
|
||||
|
||||
// make sure the messenger is initialized
|
||||
status_t error = _InitMessenger();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// send the request
|
||||
error = fServerMessenger.SendMessage(request, reply);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// check the reply result
|
||||
status_t result;
|
||||
if (reply->FindInt32("error", &result) != B_OK)
|
||||
return B_ERROR;
|
||||
return result;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
// NetFSServerRoster.h
|
||||
|
||||
#ifndef NETFS_SERVER_ROSTER_H
|
||||
#define NETFS_SERVER_ROSTER_H
|
||||
|
||||
#include <Messenger.h>
|
||||
#include <OS.h>
|
||||
|
||||
class NetFSServerRoster {
|
||||
public:
|
||||
NetFSServerRoster();
|
||||
~NetFSServerRoster();
|
||||
|
||||
// server
|
||||
bool IsServerRunning();
|
||||
status_t LaunchServer();
|
||||
status_t TerminateServer(bool force = false,
|
||||
bigtime_t timeout = B_INFINITE_TIMEOUT);
|
||||
status_t SaveServerSettings();
|
||||
|
||||
// users
|
||||
status_t AddUser(const char* user, const char* password);
|
||||
status_t RemoveUser(const char* user);
|
||||
status_t GetUsers(BMessage* users);
|
||||
status_t GetUserStatistics(const char* user,
|
||||
BMessage* statistics);
|
||||
|
||||
// shares
|
||||
status_t AddShare(const char* share, const char* path);
|
||||
status_t RemoveShare(const char* share);
|
||||
status_t GetShares(BMessage* shares);
|
||||
status_t GetShareUsers(const char* share,
|
||||
BMessage* users);
|
||||
status_t GetShareStatistics(const char* share,
|
||||
BMessage* statistics);
|
||||
|
||||
// permissions
|
||||
status_t SetUserPermissions(const char* share,
|
||||
const char* user, uint32 permissions);
|
||||
status_t GetUserPermissions(const char* share,
|
||||
const char* user, uint32* permissions);
|
||||
|
||||
private:
|
||||
status_t _InitMessenger();
|
||||
status_t _SendRequest(BMessage* request,
|
||||
BMessage* reply = NULL);
|
||||
|
||||
private:
|
||||
BMessenger fServerMessenger;
|
||||
};
|
||||
|
||||
#endif // NETFS_SERVER_ROSTER_H
|
@ -0,0 +1,368 @@
|
||||
// AttributeDirectory.cpp
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <Node.h>
|
||||
|
||||
#include "AttributeDirectory.h"
|
||||
|
||||
// small data size
|
||||
static const int32 kSmallAttributeSize = 8;
|
||||
|
||||
// constructor
|
||||
Attribute::Attribute(const char* name, const attr_info& info,
|
||||
const void* data)
|
||||
: fInfo(info)
|
||||
{
|
||||
char* nameBuffer = fDataAndName;
|
||||
|
||||
// copy data, if any
|
||||
if (data) {
|
||||
nameBuffer += info.size;
|
||||
memcpy(fDataAndName, data, info.size);
|
||||
|
||||
// store a negative size to indicate we also have the data
|
||||
fInfo.size = -info.size;
|
||||
}
|
||||
|
||||
// copy the name
|
||||
strcpy(nameBuffer, name);
|
||||
}
|
||||
|
||||
// destructor
|
||||
Attribute::~Attribute()
|
||||
{
|
||||
}
|
||||
|
||||
// CreateAttribute
|
||||
status_t
|
||||
Attribute::CreateAttribute(const char* name, const attr_info& info,
|
||||
const void* data, Attribute** attribute)
|
||||
{
|
||||
if (!name || !attribute)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// compute the size
|
||||
int32 nameLen = strlen(name);
|
||||
int32 size = sizeof(Attribute) + nameLen;
|
||||
if (data)
|
||||
size += info.size;
|
||||
|
||||
void* buffer = malloc(size);
|
||||
if (!buffer)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
*attribute = new(buffer) Attribute(name, info, data);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// DeleteAttribute
|
||||
void
|
||||
Attribute::DeleteAttribute(Attribute* attribute)
|
||||
{
|
||||
if (attribute) {
|
||||
attribute->~Attribute();
|
||||
free(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
// GetName
|
||||
const char*
|
||||
Attribute::GetName() const
|
||||
{
|
||||
return (fInfo.size >= 0 ? fDataAndName : fDataAndName - fInfo.size);
|
||||
}
|
||||
|
||||
// GetInfo
|
||||
void
|
||||
Attribute::GetInfo(attr_info* info) const
|
||||
{
|
||||
if (info) {
|
||||
info->type = fInfo.type;
|
||||
info->size = GetSize();
|
||||
}
|
||||
}
|
||||
|
||||
// GetType
|
||||
uint32
|
||||
Attribute::GetType() const
|
||||
{
|
||||
return fInfo.type;
|
||||
}
|
||||
|
||||
// GetSize
|
||||
off_t
|
||||
Attribute::GetSize() const
|
||||
{
|
||||
return (fInfo.size >= 0 ? fInfo.size : -fInfo.size);
|
||||
}
|
||||
|
||||
// GetData
|
||||
const void*
|
||||
Attribute::GetData() const
|
||||
{
|
||||
return (fInfo.size >= 0 ? NULL : fDataAndName);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
AttributeDirectory::AttributeDirectory()
|
||||
: fAttributes(),
|
||||
fStatus(ATTRIBUTE_DIRECTORY_NOT_LOADED)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
AttributeDirectory::~AttributeDirectory()
|
||||
{
|
||||
ClearAttrDir();
|
||||
}
|
||||
|
||||
// GetAttrDirStatus
|
||||
uint32
|
||||
AttributeDirectory::GetAttrDirStatus() const
|
||||
{
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
// IsAttrDirValid
|
||||
bool
|
||||
AttributeDirectory::IsAttrDirValid() const
|
||||
{
|
||||
return (fStatus == ATTRIBUTE_DIRECTORY_VALID);
|
||||
}
|
||||
|
||||
// LoadAttrDir
|
||||
status_t
|
||||
AttributeDirectory::LoadAttrDir()
|
||||
{
|
||||
// nothing to do, if already loaded
|
||||
if (fStatus == ATTRIBUTE_DIRECTORY_VALID)
|
||||
return B_OK;
|
||||
|
||||
// if we tried earlier and the attr dir was too big, we fail again
|
||||
if (fStatus == ATTRIBUTE_DIRECTORY_TOO_BIG)
|
||||
return B_ERROR;
|
||||
|
||||
// open the node
|
||||
BNode node;
|
||||
status_t error = OpenNode(node);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// iterate through the attribute directory
|
||||
char name[B_ATTR_NAME_LENGTH];
|
||||
while (node.GetNextAttrName(name) == B_OK) {
|
||||
// get the attribute data
|
||||
attr_info info;
|
||||
char data[kSmallAttributeSize];
|
||||
bool dataLoaded = false;
|
||||
error = _LoadAttribute(node, name, info, data, dataLoaded);
|
||||
if (error != B_OK)
|
||||
break;
|
||||
|
||||
// create the attribute
|
||||
error = AddAttribute(name, info, (dataLoaded ? data : NULL));
|
||||
}
|
||||
|
||||
if (error != B_OK)
|
||||
ClearAttrDir();
|
||||
// TODO: Enforce maximum attribute directory size.
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// ClearAttrDir
|
||||
void
|
||||
AttributeDirectory::ClearAttrDir()
|
||||
{
|
||||
while (Attribute* attribute = GetFirstAttribute())
|
||||
RemoveAttribute(attribute);
|
||||
}
|
||||
|
||||
// AddAttribute
|
||||
status_t
|
||||
AttributeDirectory::AddAttribute(const char* name, const attr_info& info,
|
||||
const void* data)
|
||||
{
|
||||
if (!name || GetAttribute(name))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// create the attribute
|
||||
Attribute* attribute;
|
||||
status_t error = Attribute::CreateAttribute(name, info, data, &attribute);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// add the attribute
|
||||
fAttributes.Insert(attribute);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// RemoveAttribute
|
||||
bool
|
||||
AttributeDirectory::RemoveAttribute(const char* name)
|
||||
{
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
for (SLList<Attribute>::Iterator it = fAttributes.GetIterator();
|
||||
it.HasNext();) {
|
||||
Attribute* attribute = it.Next();
|
||||
if (strcmp(attribute->GetName(), name) == 0) {
|
||||
it.Remove();
|
||||
Attribute::DeleteAttribute(attribute);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveAttribute
|
||||
void
|
||||
AttributeDirectory::RemoveAttribute(Attribute* attribute)
|
||||
{
|
||||
if (!attribute)
|
||||
return;
|
||||
|
||||
fAttributes.Remove(attribute);
|
||||
Attribute::DeleteAttribute(attribute);
|
||||
}
|
||||
|
||||
// UpdateAttribute
|
||||
status_t
|
||||
AttributeDirectory::UpdateAttribute(const char* name, bool* removed,
|
||||
attr_info* _info, const void** _data)
|
||||
{
|
||||
if (!name || !removed)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// open the node
|
||||
BNode node;
|
||||
status_t error = OpenNode(node);
|
||||
if (error != B_OK) {
|
||||
ClearAttrDir();
|
||||
if (fStatus == ATTRIBUTE_DIRECTORY_VALID)
|
||||
fStatus = ATTRIBUTE_DIRECTORY_NOT_LOADED;
|
||||
return error;
|
||||
}
|
||||
|
||||
// get the attribute data
|
||||
attr_info info;
|
||||
char data[kSmallAttributeSize];
|
||||
bool dataLoaded = false;
|
||||
error = _LoadAttribute(node, name, info,
|
||||
(fStatus == ATTRIBUTE_DIRECTORY_VALID ? data : NULL), dataLoaded);
|
||||
if (error == B_OK) {
|
||||
if (fStatus == ATTRIBUTE_DIRECTORY_VALID) {
|
||||
// remove the attribute
|
||||
Attribute* previous = NULL;
|
||||
for (SLList<Attribute>::Iterator it = fAttributes.GetIterator();
|
||||
it.HasNext();) {
|
||||
Attribute* attribute = it.Next();
|
||||
if (strcmp(attribute->GetName(), name) == 0) {
|
||||
it.Remove();
|
||||
Attribute::DeleteAttribute(attribute);
|
||||
break;
|
||||
}
|
||||
previous = attribute;
|
||||
}
|
||||
|
||||
// TODO: Enforce the maximum attr dir size.
|
||||
// re-create the attribute
|
||||
Attribute* attribute;
|
||||
error = Attribute::CreateAttribute(name, info, data,
|
||||
&attribute);
|
||||
if (error == B_OK) {
|
||||
// add the attribute
|
||||
fAttributes.InsertAfter(previous, attribute);
|
||||
|
||||
// return the desired info
|
||||
if (_info)
|
||||
attribute->GetInfo(_info);
|
||||
if (_data)
|
||||
*_data = attribute->GetData();
|
||||
*removed = false;
|
||||
}
|
||||
} else if (error == B_OK) {
|
||||
if (_info)
|
||||
*_info = info;
|
||||
if (_data)
|
||||
*_data = NULL;
|
||||
*removed = false;
|
||||
}
|
||||
} else {
|
||||
*removed = true;
|
||||
RemoveAttribute(name);
|
||||
error = B_OK;
|
||||
}
|
||||
|
||||
// clean up on error
|
||||
if (error != B_OK) {
|
||||
ClearAttrDir();
|
||||
if (fStatus == ATTRIBUTE_DIRECTORY_VALID)
|
||||
fStatus = ATTRIBUTE_DIRECTORY_NOT_LOADED;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// GetAttribute
|
||||
Attribute*
|
||||
AttributeDirectory::GetAttribute(const char* name) const
|
||||
{
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
for (SLList<Attribute>::ConstIterator it = fAttributes.GetIterator();
|
||||
it.HasNext();) {
|
||||
Attribute* attribute = it.Next();
|
||||
if (strcmp(attribute->GetName(), name) == 0)
|
||||
return attribute;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// GetFirstAttribute
|
||||
Attribute*
|
||||
AttributeDirectory::GetFirstAttribute() const
|
||||
{
|
||||
return fAttributes.GetFirst();
|
||||
}
|
||||
|
||||
// GetNextAttribute
|
||||
Attribute*
|
||||
AttributeDirectory::GetNextAttribute(Attribute* attribute) const
|
||||
{
|
||||
return (attribute ? fAttributes.GetNext(attribute) : NULL);
|
||||
}
|
||||
|
||||
// _LoadAttribute
|
||||
status_t
|
||||
AttributeDirectory::_LoadAttribute(BNode& node, const char* name,
|
||||
attr_info& info, void* data, bool& dataLoaded)
|
||||
{
|
||||
// stat the attribute
|
||||
status_t error = node.GetAttrInfo(name, &info);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// if the data are small enough, read them
|
||||
if (data && info.size <= kSmallAttributeSize) {
|
||||
ssize_t bytesRead = node.ReadAttr(name, info.type, 0, data,
|
||||
info.size);
|
||||
dataLoaded = (bytesRead == info.size);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -0,0 +1,75 @@
|
||||
// AttributeDirectory.h
|
||||
|
||||
#ifndef NET_FS_ATTRIBUTE_DIRECTORY_H
|
||||
#define NET_FS_ATTRIBUTE_DIRECTORY_H
|
||||
|
||||
#include <fs_attr.h>
|
||||
|
||||
#include "SLList.h"
|
||||
|
||||
class BNode;
|
||||
|
||||
// attribute directory status
|
||||
enum {
|
||||
ATTRIBUTE_DIRECTORY_NOT_LOADED,
|
||||
ATTRIBUTE_DIRECTORY_VALID,
|
||||
ATTRIBUTE_DIRECTORY_TOO_BIG,
|
||||
};
|
||||
|
||||
// Attribute
|
||||
class Attribute : public SLListLinkImpl<Attribute> {
|
||||
Attribute(const char* name,
|
||||
const attr_info& info, const void* data);
|
||||
~Attribute();
|
||||
public:
|
||||
static status_t CreateAttribute(const char* name,
|
||||
const attr_info& info, const void* data,
|
||||
Attribute** attribute);
|
||||
static void DeleteAttribute(Attribute* attribute);
|
||||
|
||||
const char* GetName() const;
|
||||
void GetInfo(attr_info* info) const;
|
||||
uint32 GetType() const;
|
||||
off_t GetSize() const;
|
||||
const void* GetData() const;
|
||||
|
||||
private:
|
||||
attr_info fInfo;
|
||||
char fDataAndName[1];
|
||||
};
|
||||
|
||||
// AttributeDirectory
|
||||
class AttributeDirectory {
|
||||
public:
|
||||
AttributeDirectory();
|
||||
virtual ~AttributeDirectory();
|
||||
|
||||
uint32 GetAttrDirStatus() const;
|
||||
bool IsAttrDirValid() const;
|
||||
|
||||
status_t LoadAttrDir();
|
||||
void ClearAttrDir();
|
||||
|
||||
status_t AddAttribute(const char* name,
|
||||
const attr_info& info, const void* data);
|
||||
bool RemoveAttribute(const char* name);
|
||||
void RemoveAttribute(Attribute* attribute);
|
||||
status_t UpdateAttribute(const char* name, bool* removed,
|
||||
attr_info* info, const void** data);
|
||||
Attribute* GetAttribute(const char* name) const;
|
||||
Attribute* GetFirstAttribute() const;
|
||||
Attribute* GetNextAttribute(Attribute* attribute) const;
|
||||
|
||||
virtual status_t OpenNode(BNode& node) = 0;
|
||||
|
||||
private:
|
||||
status_t _LoadAttribute(BNode& node, const char* name,
|
||||
attr_info& info, void* data,
|
||||
bool& dataLoaded);
|
||||
|
||||
private:
|
||||
SLList<Attribute> fAttributes;
|
||||
uint32 fStatus;
|
||||
};
|
||||
|
||||
#endif // NET_FS_ATTRIBUTE_DIRECTORY_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user