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:
Stephan Aßmus 2010-01-14 21:56:16 +00:00
parent 783a5c71b1
commit 5a1d355fdf
186 changed files with 36140 additions and 0 deletions

View File

@ -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 ;

View 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 ;

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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
;

View File

@ -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));
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View 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
;

View 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;
}

View 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

View 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);
}
}

View 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

View 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);
}
}
}

View 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

View 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;
}

View 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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View 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()
{
}

View 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

View File

@ -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++];
}

View File

@ -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

View 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;
}

View 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

View 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;
}

View 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

View File

@ -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);
}

View File

@ -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

View 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);
}

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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);
}

View 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

View 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;
}

View 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

View 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;
}

View 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

View 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()
{
}

View 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

View 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;
}

View 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

View 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

View 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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View 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
# }
#}

View 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
;

View File

@ -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, &params) < 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, &params) < 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);
}

View File

@ -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
;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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