Copied userlandfs code from the test tree to the haiku source tree,

where it will be ported to Haiku.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20216 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2007-02-24 00:30:19 +00:00
parent d5e020e912
commit 83812f6752
96 changed files with 25005 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
/*
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#ifndef _CACHE_H_
#define _CACHE_H_
#include <BeBuild.h>
#include "lock.h"
#ifndef _IMPEXP_KERNEL
#define _IMPEXP_KERNEL
#endif
typedef struct hash_ent {
int dev;
off_t bnum;
off_t hash_val;
void *data;
struct hash_ent *next;
} hash_ent;
typedef struct hash_table {
hash_ent **table;
int max;
int mask; /* == max - 1 */
int num_elements;
} hash_table;
#define HT_DEFAULT_MAX 128
typedef struct cache_ent {
int dev;
off_t block_num;
int bsize;
volatile int flags;
void *data;
void *clone; /* copy of data by set_block_info() */
int lock;
void (*func)(off_t bnum, size_t num_blocks, void *arg);
off_t logged_bnum;
void *arg;
struct cache_ent *next, /* points toward mru end of list */
*prev; /* points toward lru end of list */
} cache_ent;
#define CE_NORMAL 0x0000 /* a nice clean pristine page */
#define CE_DIRTY 0x0002 /* needs to be written to disk */
#define CE_BUSY 0x0004 /* this block has i/o happening, don't touch it */
typedef struct cache_ent_list {
cache_ent *lru; /* tail of the list */
cache_ent *mru; /* head of the list */
} cache_ent_list;
typedef struct block_cache {
struct lock lock;
int flags;
int cur_blocks;
int max_blocks;
hash_table ht;
cache_ent_list normal, /* list of "normal" blocks (clean & dirty) */
locked; /* list of clean and locked blocks */
} block_cache;
#if 0 /* XXXdbg -- need to deal with write through caches */
#define DC_WRITE_THROUGH 0x0001 /* cache is write-through (for floppies) */
#endif
#define ALLOW_WRITES 1
#define NO_WRITES 0
#ifdef __cplusplus
extern "C" {
#endif
extern _IMPEXP_KERNEL int init_block_cache(int max_blocks, int flags);
extern _IMPEXP_KERNEL void shutdown_block_cache(void);
extern _IMPEXP_KERNEL void force_cache_flush(int dev, int prefer_log_blocks);
extern _IMPEXP_KERNEL int flush_blocks(int dev, off_t bnum, int nblocks);
extern _IMPEXP_KERNEL int flush_device(int dev, int warn_locked);
extern _IMPEXP_KERNEL int init_cache_for_device(int fd, off_t max_blocks);
extern _IMPEXP_KERNEL int remove_cached_device_blocks(int dev, int allow_write);
extern _IMPEXP_KERNEL void *get_block(int dev, off_t bnum, int bsize);
extern _IMPEXP_KERNEL void *get_empty_block(int dev, off_t bnum, int bsize);
extern _IMPEXP_KERNEL int release_block(int dev, off_t bnum);
extern _IMPEXP_KERNEL int mark_blocks_dirty(int dev, off_t bnum, int nblocks);
extern _IMPEXP_KERNEL int cached_read(int dev, off_t bnum, void *data, off_t num_blocks, int bsize);
extern _IMPEXP_KERNEL int cached_write(int dev, off_t bnum, const void *data,
off_t num_blocks, int bsize);
extern _IMPEXP_KERNEL int cached_write_locked(int dev, off_t bnum, const void *data,
off_t num_blocks, int bsize);
extern _IMPEXP_KERNEL int set_blocks_info(int dev, off_t *blocks, int nblocks,
void (*func)(off_t bnum, size_t nblocks, void *arg),
void *arg);
extern _IMPEXP_KERNEL size_t read_phys_blocks (int fd, off_t bnum, void *data, uint num_blocks, int bsize);
extern _IMPEXP_KERNEL size_t write_phys_blocks(int fd, off_t bnum, void *data, uint num_blocks, int bsize);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* _CACHE_H_ */
+258
View File
@@ -0,0 +1,258 @@
#ifndef _FSPROTO_H
#define _FSPROTO_H
#include <sys/dirent.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iovec.h>
#include <OS.h>
#include <fs_attr.h>
#include <fs_info.h>
#include <BeBuild.h>
#include <Drivers.h>
#ifndef _IMPEXP_KERNEL
#define _IMPEXP_KERNEL
#endif
typedef dev_t nspace_id;
typedef ino_t vnode_id;
/*
* PUBLIC PART OF THE FILE SYSTEM PROTOCOL
*/
#define WSTAT_MODE 0x0001
#define WSTAT_UID 0x0002
#define WSTAT_GID 0x0004
#define WSTAT_SIZE 0x0008
#define WSTAT_ATIME 0x0010
#define WSTAT_MTIME 0x0020
#define WSTAT_CRTIME 0x0040
#define WFSSTAT_NAME 0x0001
#define B_ENTRY_CREATED 1
#define B_ENTRY_REMOVED 2
#define B_ENTRY_MOVED 3
#define B_STAT_CHANGED 4
#define B_ATTR_CHANGED 5
#define B_DEVICE_MOUNTED 6
#define B_DEVICE_UNMOUNTED 7
#define B_STOP_WATCHING 0x0000
#define B_WATCH_NAME 0x0001
#define B_WATCH_STAT 0x0002
#define B_WATCH_ATTR 0x0004
#define B_WATCH_DIRECTORY 0x0008
#define SELECT_READ 1
#define SELECT_WRITE 2
#define SELECT_EXCEPTION 3
// missing ioctl() call added
#define IOCTL_FILE_UNCACHED_IO 10000
#define IOCTL_CREATE_TIME 10002
#define IOCTL_MODIFIED_TIME 10003
#define B_CUR_FS_API_VERSION 2
struct attr_info;
struct index_info;
typedef int op_read_vnode(void *ns, vnode_id vnid, char r, void **node);
typedef int op_write_vnode(void *ns, void *node, char r);
typedef int op_remove_vnode(void *ns, void *node, char r);
typedef int op_secure_vnode(void *ns, void *node);
typedef int op_walk(void *ns, void *base, const char *file, char **newpath,
vnode_id *vnid);
typedef int op_access(void *ns, void *node, int mode);
typedef int op_create(void *ns, void *dir, const char *name,
int omode, int perms, vnode_id *vnid, void **cookie);
typedef int op_mkdir(void *ns, void *dir, const char *name, int perms);
typedef int op_symlink(void *ns, void *dir, const char *name,
const char *path);
typedef int op_link(void *ns, void *dir, const char *name, void *node);
typedef int op_rename(void *ns, void *olddir, const char *oldname,
void *newdir, const char *newname);
typedef int op_unlink(void *ns, void *dir, const char *name);
typedef int op_rmdir(void *ns, void *dir, const char *name);
typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize);
typedef int op_opendir(void *ns, void *node, void **cookie);
typedef int op_closedir(void *ns, void *node, void *cookie);
typedef int op_rewinddir(void *ns, void *node, void *cookie);
typedef int op_readdir(void *ns, void *node, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef int op_open(void *ns, void *node, int omode, void **cookie);
typedef int op_close(void *ns, void *node, void *cookie);
typedef int op_free_cookie(void *ns, void *node, void *cookie);
typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf,
size_t *len);
typedef int op_write(void *ns, void *node, void *cookie, off_t pos,
const void *buf, size_t *len);
typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
size_t count, size_t *len);
typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
size_t count, size_t *len);
typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf,
size_t len);
typedef int op_setflags(void *ns, void *node, void *cookie, int flags);
typedef int op_rstat(void *ns, void *node, struct stat *);
typedef int op_wstat(void *ns, void *node, struct stat *, long mask);
typedef int op_fsync(void *ns, void *node);
typedef int op_select(void *ns, void *node, void *cookie, uint8 event,
uint32 ref, selectsync *sync);
typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event,
selectsync *sync);
typedef int op_initialize(const char *devname, void *parms, size_t len);
typedef int op_mount(nspace_id nsid, const char *devname, ulong flags,
void *parms, size_t len, void **data, vnode_id *vnid);
typedef int op_unmount(void *ns);
typedef int op_sync(void *ns);
typedef int op_rfsstat(void *ns, struct fs_info *);
typedef int op_wfsstat(void *ns, struct fs_info *, long mask);
typedef int op_open_attrdir(void *ns, void *node, void **cookie);
typedef int op_close_attrdir(void *ns, void *node, void *cookie);
typedef int op_rewind_attrdir(void *ns, void *node, void *cookie);
typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef int op_remove_attr(void *ns, void *node, const char *name);
typedef int op_rename_attr(void *ns, void *node, const char *oldname,
const char *newname);
typedef int op_stat_attr(void *ns, void *node, const char *name,
struct attr_info *buf);
typedef int op_write_attr(void *ns, void *node, const char *name, int type,
const void *buf, size_t *len, off_t pos);
typedef int op_read_attr(void *ns, void *node, const char *name, int type,
void *buf, size_t *len, off_t pos);
typedef int op_open_indexdir(void *ns, void **cookie);
typedef int op_close_indexdir(void *ns, void *cookie);
typedef int op_rewind_indexdir(void *ns, void *cookie);
typedef int op_read_indexdir(void *ns, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef int op_create_index(void *ns, const char *name, int type, int flags);
typedef int op_remove_index(void *ns, const char *name);
typedef int op_rename_index(void *ns, const char *oldname,
const char *newname);
typedef int op_stat_index(void *ns, const char *name, struct index_info *buf);
typedef int op_open_query(void *ns, const char *query, ulong flags,
port_id port, long token, void **cookie);
typedef int op_close_query(void *ns, void *cookie);
typedef int op_read_query(void *ns, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef struct vnode_ops {
op_read_vnode (*read_vnode);
op_write_vnode (*write_vnode);
op_remove_vnode (*remove_vnode);
op_secure_vnode (*secure_vnode);
op_walk (*walk);
op_access (*access);
op_create (*create);
op_mkdir (*mkdir);
op_symlink (*symlink);
op_link (*link);
op_rename (*rename);
op_unlink (*unlink);
op_rmdir (*rmdir);
op_readlink (*readlink);
op_opendir (*opendir);
op_closedir (*closedir);
op_free_cookie (*free_dircookie);
op_rewinddir (*rewinddir);
op_readdir (*readdir);
op_open (*open);
op_close (*close);
op_free_cookie (*free_cookie);
op_read (*read);
op_write (*write);
op_readv (*readv);
op_writev (*writev);
op_ioctl (*ioctl);
op_setflags (*setflags);
op_rstat (*rstat);
op_wstat (*wstat);
op_fsync (*fsync);
op_initialize (*initialize);
op_mount (*mount);
op_unmount (*unmount);
op_sync (*sync);
op_rfsstat (*rfsstat);
op_wfsstat (*wfsstat);
op_select (*select);
op_deselect (*deselect);
op_open_indexdir (*open_indexdir);
op_close_indexdir (*close_indexdir);
op_free_cookie (*free_indexdircookie);
op_rewind_indexdir (*rewind_indexdir);
op_read_indexdir (*read_indexdir);
op_create_index (*create_index);
op_remove_index (*remove_index);
op_rename_index (*rename_index);
op_stat_index (*stat_index);
op_open_attrdir (*open_attrdir);
op_close_attrdir (*close_attrdir);
op_free_cookie (*free_attrdircookie);
op_rewind_attrdir (*rewind_attrdir);
op_read_attrdir (*read_attrdir);
op_write_attr (*write_attr);
op_read_attr (*read_attr);
op_remove_attr (*remove_attr);
op_rename_attr (*rename_attr);
op_stat_attr (*stat_attr);
op_open_query (*open_query);
op_close_query (*close_query);
op_free_cookie (*free_querycookie);
op_read_query (*read_query);
} vnode_ops;
#ifdef __cplusplus
extern "C" {
#endif
extern _IMPEXP_KERNEL int new_path(const char *path, char **copy);
extern _IMPEXP_KERNEL void free_path(char *p);
extern _IMPEXP_KERNEL int notify_listener(int op, nspace_id nsid,
vnode_id vnida, vnode_id vnidb,
vnode_id vnidc, const char *name);
extern _IMPEXP_KERNEL void notify_select_event(selectsync *sync, uint32 ref);
extern _IMPEXP_KERNEL int send_notification(port_id port, long token,
ulong what, long op, nspace_id nsida,
nspace_id nsidb, vnode_id vnida,
vnode_id vnidb, vnode_id vnidc,
const char *name);
extern _IMPEXP_KERNEL int get_vnode(nspace_id nsid, vnode_id vnid, void **data);
extern _IMPEXP_KERNEL int put_vnode(nspace_id nsid, vnode_id vnid);
extern _IMPEXP_KERNEL int new_vnode(nspace_id nsid, vnode_id vnid, void *data);
extern _IMPEXP_KERNEL int remove_vnode(nspace_id nsid, vnode_id vnid);
extern _IMPEXP_KERNEL int unremove_vnode(nspace_id nsid, vnode_id vnid);
extern _IMPEXP_KERNEL int is_vnode_removed(nspace_id nsid, vnode_id vnid);
extern _EXPORT vnode_ops fs_entry;
extern _EXPORT int32 api_version;
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+55
View File
@@ -0,0 +1,55 @@
/*
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#ifndef _LOCK_H
#define _LOCK_H
#include <BeBuild.h>
#include <OS.h>
#ifndef _IMPEXP_KERNEL
#define _IMPEXP_KERNEL
#endif
#ifdef __cplusplus
extern "C" {
#else
typedef struct lock lock;
typedef struct mlock mlock;
#endif
struct lock {
sem_id s;
long c;
};
struct mlock {
sem_id s;
};
extern _IMPEXP_KERNEL int new_lock(lock *l, const char *name);
extern _IMPEXP_KERNEL int free_lock(lock *l);
#ifdef LOCK
#undef LOCK
#endif
#define LOCK(l) if (atomic_add(&l.c, -1) <= 0) acquire_sem(l.s);
#define UNLOCK(l) if (atomic_add(&l.c, 1) < 0) release_sem(l.s);
extern _IMPEXP_KERNEL int new_mlock(mlock *l, long c, const char *name);
extern _IMPEXP_KERNEL int free_mlock(mlock *l);
#define LOCKM(l,cnt) acquire_sem_etc(l.s, cnt, 0, 0)
#define UNLOCKM(l,cnt) release_sem_etc(l.s, cnt, 0)
#ifdef __cplusplus
} // extern "C"
#endif
#endif
@@ -0,0 +1,17 @@
// AreaSupport.h
#ifndef USERLAND_FS_AREA_SUPPORT_H
#define USERLAND_FS_AREA_SUPPORT_H
#include <OS.h>
namespace UserlandFSUtil {
status_t get_area_for_address(void* address, int32 size, area_id* area,
int32* offset, void** areaBaseAddress = NULL);
} // namespace UserlandFSUtil
using UserlandFSUtil::get_area_for_address;
#endif // USERLAND_FS_AREA_SUPPORT_H
@@ -0,0 +1,21 @@
// DispatcherDefs.h
#ifndef USERLAND_FS_DISPATCHER_DEFS_H
#define USERLAND_FS_DISPATCHER_DEFS_H
namespace UserlandFSUtil {
extern const char* kUserlandFSDispatcherPortName;
extern const char* kUserlandFSDispatcherReplyPortName;
} // namespace UserlandFSUtil
using UserlandFSUtil::kUserlandFSDispatcherPortName;
using UserlandFSUtil::kUserlandFSDispatcherReplyPortName;
enum {
UFS_DISPATCHER_CONNECT = 'cnct',
UFS_DISPATCHER_CONNECT_ACK = 'cack',
};
#endif // USERLAND_FS_DISPATCHER_DEFS_H
+58
View File
@@ -0,0 +1,58 @@
// Port.h
#ifndef USERLAND_FS_PORT_H
#define USERLAND_FS_PORT_H
#include <OS.h>
namespace UserlandFSUtil {
struct PortInfo {
};
class Port {
public:
struct Info {
port_id owner_port;
port_id client_port;
int32 size;
};
public:
Port(int32 size);
Port(const Info* info);
~Port();
void Close();
status_t InitCheck() const;
const Info* GetInfo() const;
void* GetBuffer() const;
int32 GetCapacity() const;
void* GetMessage() const;
int32 GetMessageSize() const;
status_t Send(int32 size);
status_t SendAndReceive(int32 size);
status_t Receive(bigtime_t timeout = -1);
private:
friend class KernelDebug;
Info fInfo;
uint8* fBuffer;
int32 fCapacity;
int32 fMessageSize;
status_t fInitStatus;
bool fOwner;
};
} // namespace UserlandFSUtil
using UserlandFSUtil::PortInfo;
using UserlandFSUtil::Port;
#endif // USERLAND_FS_PORT_H
@@ -0,0 +1,84 @@
// Request.h
#ifndef USERLAND_FS_REQUEST_H
#define USERLAND_FS_REQUEST_H
#include <OS.h>
// address info flags
enum {
ADDRESS_NOT_NULL = 0x01,
ADDRESS_IS_STRING = 0x02,
};
namespace UserlandFSUtil {
class RequestAllocator;
// Address
class Address {
public:
Address();
void* GetData() const { return fRelocated; }
int32 GetSize() const { return fSize; }
//private:
void SetTo(area_id area, int32 offset, int32 size);
void SetRelocatedAddress(void* address)
{ fRelocated = address; }
area_id GetArea() const { return fUnrelocated.area; }
int32 GetOffset() const
{ return fUnrelocated.offset; }
private:
friend class RequestAllocator;
struct Unrelocated {
area_id area;
int32 offset;
};
union {
Unrelocated fUnrelocated;
void* fRelocated;
};
int32 fSize;
};
// AddressInfo
struct AddressInfo {
Address *address;
uint32 flags;
int32 max_size;
};
// Request
class Request {
public:
Request(uint32 type);
uint32 GetType() const;
status_t Check() const;
status_t GetAddressInfos(AddressInfo* infos,
int32* count);
private:
uint32 fType;
};
// implemented in Requests.cpp
bool is_kernel_request(uint32 type);
bool is_userland_request(uint32 type);
} // namespace UserlandFSUtil
using UserlandFSUtil::Address;
using UserlandFSUtil::AddressInfo;
using UserlandFSUtil::Request;
using UserlandFSUtil::is_kernel_request;
using UserlandFSUtil::is_userland_request;
#endif // USERLAND_FS_REQUEST_H
@@ -0,0 +1,89 @@
// RequestAllocator.h
#ifndef USERLAND_FS_REQUEST_ALLOCATOR_H
#define USERLAND_FS_REQUEST_ALLOCATOR_H
#include <new>
#include <OS.h>
#include "Debug.h"
#include "Requests.h"
namespace UserlandFSUtil {
class Port;
// RequestAllocator
class RequestAllocator {
public:
RequestAllocator(Port* port);
~RequestAllocator();
status_t Init(Port* port);
void Uninit();
status_t Error() const;
void FinishDeferredInit();
status_t AllocateRequest(int32 size);
status_t ReadRequest();
Request* GetRequest() const;
int32 GetRequestSize() const;
status_t AllocateAddress(Address& address, int32 size,
int32 align, void** data,
bool deferredInit = false);
status_t AllocateData(Address& address, const void* data,
int32 size, int32 align,
bool deferredInit = false);
status_t AllocateString(Address& address,
const char* data,
bool deferredInit = false);
// status_t SetAddress(Address& address, void* data,
// int32 size = 0);
private:
struct DeferredInitInfo {
Address* target;
uint8* data; // only if in port buffer
area_id area; // only if in area, otherwise -1
int32 offset;
int32 size;
bool inPortBuffer;
};
status_t fError;
Port* fPort;
Request* fRequest;
int32 fRequestSize;
area_id fAllocatedAreas[MAX_REQUEST_ADDRESS_COUNT];
int32 fAllocatedAreaCount;
DeferredInitInfo fDeferredInitInfos[MAX_REQUEST_ADDRESS_COUNT];
int32 fDeferredInitInfoCount;
bool fRequestInPortBuffer;
};
// AllocateRequest
// Should be a member, but we don't have member templates on PPC.
// TODO: Actually we seem to have. Check!
template<typename SpecificRequest>
status_t
AllocateRequest(RequestAllocator& allocator, SpecificRequest** request)
{
if (!request)
RETURN_ERROR(B_BAD_VALUE);
status_t error = allocator.AllocateRequest(sizeof(SpecificRequest));
if (error == B_OK)
*request = new(allocator.GetRequest()) SpecificRequest;
return error;
}
} // namespace UserlandFSUtil
using UserlandFSUtil::RequestAllocator;
using UserlandFSUtil::AllocateRequest;
#endif // USERLAND_FS_REQUEST_ALLOCATOR_H
@@ -0,0 +1,35 @@
// RequestHandler.h
#ifndef USERLAND_FS_REQUEST_HANDLER_H
#define USERLAND_FS_REQUEST_HANDLER_H
#include <SupportDefs.h>
namespace UserlandFSUtil {
class Request;
class RequestPort;
class RequestHandler {
public:
RequestHandler();
virtual ~RequestHandler();
void SetPort(RequestPort* port);
bool IsDone() const;
virtual status_t HandleRequest(Request* request) = 0;
protected:
RequestPort* fPort;
bool fDone;
};
} // namespace UserlandFSUtil
using UserlandFSUtil::Request;
using UserlandFSUtil::RequestHandler;
using UserlandFSUtil::RequestPort;
#endif // USERLAND_FS_REQUEST_HANDLER_H
@@ -0,0 +1,73 @@
// RequestPort.h
#ifndef USERLAND_FS_REQUEST_PORT_H
#define USERLAND_FS_REQUEST_PORT_H
#include "Port.h"
#include "RequestAllocator.h"
namespace UserlandFSUtil {
class RequestHandler;
// RequestPort
class RequestPort {
public:
RequestPort(int32 size);
RequestPort(const Port::Info* info);
~RequestPort();
void Close();
status_t InitCheck() const;
Port* GetPort();
const Port::Info* GetPortInfo() const;
status_t SendRequest(RequestAllocator* allocator);
status_t SendRequest(RequestAllocator* allocator,
RequestHandler* handler,
Request** reply = NULL,
bigtime_t timeout = -1);
status_t ReceiveRequest(Request** request,
bigtime_t timeout = -1);
status_t HandleRequests(RequestHandler* handler,
Request** reply = NULL,
bigtime_t timeout = -1);
void ReleaseRequest(Request* request);
private:
void _PopAllocator();
private:
friend class KernelDebug;
struct AllocatorNode;
Port fPort;
AllocatorNode* fCurrentAllocatorNode;
};
// RequestReleaser
class RequestReleaser {
public:
inline RequestReleaser(RequestPort* port, Request* request)
: fPort(port), fRequest(request) {}
inline ~RequestReleaser()
{
if (fPort && fRequest)
fPort->ReleaseRequest(fRequest);
}
private:
RequestPort* fPort;
Request* fRequest;
};
} // namespace UserlandFSUtil
using UserlandFSUtil::RequestPort;
using UserlandFSUtil::RequestReleaser;
#endif // USERLAND_FS_REQUEST_PORT_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,26 @@
// SingleReplyRequestHandler.h
#ifndef USERLAND_FS_SINGLE_REPLY_REQUEST_HANDLER_H
#define USERLAND_FS_SINGLE_REPLY_REQUEST_HANDLER_H
#include "RequestHandler.h"
namespace UserlandFSUtil {
class SingleReplyRequestHandler : public RequestHandler {
public:
SingleReplyRequestHandler();
SingleReplyRequestHandler(uint32 expectedReply);
virtual status_t HandleRequest(Request* request);
private:
bool fAcceptAnyRequest;
uint32 fExpectedReply;
};
} // namespace UserlandFSUtil
using UserlandFSUtil::SingleReplyRequestHandler;
#endif // USERLAND_FS_SINGLE_REPLY_REQUEST_HANDLER_H
@@ -0,0 +1,55 @@
// userlandfs_ioctl.h
#ifndef USERLAND_FS_IOCTL_H
#define USERLAND_FS_IOCTL_H
#include <Drivers.h>
// the ioctl command we use for tunnelling our commands
enum {
USERLANDFS_IOCTL = B_DEVICE_OP_CODES_END + 666,
};
// the supported commands
enum {
USERLAND_IOCTL_PUT_ALL_PENDING_VNODES = 1,
};
// the length of the magic we use
enum {
USERLAND_IOCTL_MAGIC_LENGTH = 20,
};
// the version of the ioctl protocol
enum {
USERLAND_IOCTL_CURRENT_VERSION = 1,
};
// the errors
enum {
USERLAND_IOCTL_STILL_CONNECTED = B_ERRORS_END + 666,
USERLAND_IOCTL_VNODE_COUNTING_DISABLED,
USERLAND_IOCTL_OPEN_FILES,
USERLAND_IOCTL_OPEN_DIRECTORIES,
USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES,
USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES,
USERLAND_IOCTL_OPEN_QUERIES,
};
namespace UserlandFSUtil {
struct userlandfs_ioctl {
char magic[USERLAND_IOCTL_MAGIC_LENGTH];
int version;
int command;
status_t error;
};
extern const char kUserlandFSIOCtlMagic[USERLAND_IOCTL_MAGIC_LENGTH];
} // namespace UserlandFSUtil
using UserlandFSUtil::userlandfs_ioctl;
using UserlandFSUtil::kUserlandFSIOCtlMagic;
#endif // USERLAND_FS_IOCTL_H
@@ -0,0 +1,136 @@
//------------------------------------------------------------------------------
// Copyright (c) 2001-2004, OpenBeOS
//
// 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.
//
// File Name: AutoDeleter.h
// Author(s): Ingo Weinhold ([email protected])
// Description: Scope-based automatic deletion of objects/arrays.
// ObjectDeleter - deletes an object
// ArrayDeleter - deletes an array
// MemoryDeleter - free()s malloc()ed memory
//------------------------------------------------------------------------------
#ifndef _AUTO_DELETER_H
#define _AUTO_DELETER_H
#include <stdlib.h>
namespace BPrivate {
// AutoDeleter
template<typename C, typename Delete>
class AutoDeleter {
public:
inline AutoDeleter()
: fObject(NULL)
{
}
inline AutoDeleter(C *object)
: fObject(object)
{
}
inline ~AutoDeleter()
{
fDelete(fObject);
}
inline void SetTo(C *object)
{
fDelete(fObject);
fObject = object;
}
inline C *Detach()
{
C *object = fObject;
fObject = NULL;
return object;
}
private:
C *fObject;
Delete fDelete;
};
// ObjectDeleter
template<typename C>
struct ObjectDelete
{
inline void operator()(C *object)
{
delete object;
}
};
template<typename C>
struct ObjectDeleter : AutoDeleter<C, ObjectDelete<C> >
{
ObjectDeleter() : AutoDeleter<C, ObjectDelete<C> >() {}
ObjectDeleter(C *object) : AutoDeleter<C, ObjectDelete<C> >(object) {}
};
// ArrayDeleter
template<typename C>
struct ArrayDelete
{
inline void operator()(C *array)
{
delete[] array;
}
};
template<typename C>
struct ArrayDeleter : AutoDeleter<C, ArrayDelete<C> >
{
ArrayDeleter() : AutoDeleter<C, ArrayDelete<C> >() {}
ArrayDeleter(C *array) : AutoDeleter<C, ArrayDelete<C> >(array) {}
};
// MemoryDeleter
struct MemoryDelete
{
inline void operator()(void *memory)
{
free(memory);
}
};
struct MemoryDeleter : AutoDeleter<void, MemoryDelete >
{
MemoryDeleter() : AutoDeleter<void, MemoryDelete >() {}
MemoryDeleter(void *memory) : AutoDeleter<void, MemoryDelete >(memory) {}
};
} // namespace BPrivate
using BPrivate::ObjectDeleter;
using BPrivate::ArrayDeleter;
using BPrivate::MemoryDeleter;
#endif // _AUTO_DELETER_H
@@ -0,0 +1,164 @@
// AutoLocker.h
//
// Copyright (c) 2004, Ingo Weinhold ([email protected])
//
// 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 AUTO_LOCKER_H
#define AUTO_LOCKER_H
#include <SupportDefs.h>
// locking
// AutoLockerStandardLocking
template<typename Lockable>
class AutoLockerStandardLocking {
public:
inline bool Lock(Lockable *lockable)
{
return lockable->Lock();
}
inline void Unlock(Lockable *lockable)
{
lockable->Unlock();
}
};
// AutoLockerReadLocking
template<typename Lockable>
class AutoLockerReadLocking {
public:
inline bool Lock(Lockable *lockable)
{
return lockable->ReadLock();
}
inline void Unlock(Lockable *lockable)
{
lockable->ReadUnlock();
}
};
// AutoLockerWriteLocking
template<typename Lockable>
class AutoLockerWriteLocking {
public:
inline bool Lock(Lockable *lockable)
{
return lockable->WriteLock();
}
inline void Unlock(Lockable *lockable)
{
lockable->WriteUnlock();
}
};
// AutoLocker
template<typename Lockable,
typename Locking = AutoLockerStandardLocking<Lockable> >
class AutoLocker {
private:
typedef AutoLocker<Lockable, Locking> ThisClass;
public:
inline AutoLocker(Lockable *lockable, bool alreadyLocked = false)
: fLockable(lockable),
fLocked(fLockable && alreadyLocked)
{
if (!fLocked)
_Lock();
}
inline AutoLocker(Lockable &lockable, bool alreadyLocked = false)
: fLockable(&lockable),
fLocked(fLockable && alreadyLocked)
{
if (!fLocked)
_Lock();
}
inline ~AutoLocker()
{
Unlock();
}
inline void SetTo(Lockable *lockable, bool alreadyLocked)
{
Unlock();
fLockable = lockable;
fLocked = alreadyLocked;
if (!fLocked)
_Lock();
}
inline void SetTo(Lockable &lockable, bool alreadyLocked)
{
SetTo(&lockable, alreadyLocked);
}
inline void Unset()
{
Unlock();
}
inline AutoLocker<Lockable, Locking> &operator=(Lockable *lockable)
{
SetTo(lockable);
return *this;
}
inline AutoLocker<Lockable, Locking> &operator=(Lockable &lockable)
{
SetTo(&lockable);
return *this;
}
inline bool IsLocked() const { return fLocked; }
inline void Unlock()
{
if (fLockable && fLocked) {
fLocking.Unlock(fLockable);
fLocked = false;
}
}
inline operator bool() const { return fLocked; }
private:
inline void _Lock()
{
if (fLockable)
fLocked = fLocking.Lock(fLockable);
}
private:
Lockable *fLockable;
bool fLocked;
Locking fLocking;
};
#endif // AUTO_LOCKER_H
@@ -0,0 +1,51 @@
// Compatibility.h
//
// Copyright (c) 2004, Ingo Weinhold ([email protected])
//
// 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 USERLAND_FS_COMPATIBILITY_H
#define USERLAND_FS_COMPATIBILITY_H
#include <BeBuild.h>
#if B_BEOS_VERSION <= B_BEOS_VERSION_5
//# define B_BAD_DATA -2147483632L
#else
# ifndef closesocket
# define closesocket(fd) close(fd)
# endif
#endif
// a Haiku definition
#ifndef B_BUFFER_OVERFLOW
# define B_BUFFER_OVERFLOW EOVERFLOW
#endif
// make Zeta R5 source compatible without needing to link against libzeta.so
#ifdef find_directory
# undef find_directory
#endif
#endif // USERLAND_FS_COMPATIBILITY_H
+384
View File
@@ -0,0 +1,384 @@
// DLList.h
//
// Copyright (c) 2003, Ingo Weinhold ([email protected])
//
// 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 DL_LIST_H
#define DL_LIST_H
#include <SupportDefs.h>
namespace UserlandFSUtil {
// DLListLink
template<typename Element>
class DLListLink {
public:
DLListLink() : previous(NULL), next(NULL) {}
~DLListLink() {}
Element *previous;
Element *next;
};
// DLListLinkImpl
template<typename Element>
class DLListLinkImpl {
private:
typedef DLListLink<Element> MyLink;
public:
DLListLinkImpl() : fDLListLink() {}
~DLListLinkImpl() {}
MyLink *GetDLListLink() { return &fDLListLink; }
const MyLink *GetDLListLink() const { return &fDLListLink; }
private:
MyLink fDLListLink;
};
// DLListStandardGetLink
template<typename Element>
class DLListStandardGetLink {
private:
typedef DLListLink<Element> Link;
public:
inline Link *operator()(Element *element) const
{
return element->GetDLListLink();
}
inline const Link *operator()(const Element *element) const
{
return element->GetDLListLink();
}
};
// for convenience
#define DL_LIST_TEMPLATE_LIST template<typename Element, typename GetLink>
#define DL_LIST_CLASS_NAME DLList<Element, GetLink>
// DLList
template<typename Element, typename GetLink = DLListStandardGetLink<Element> >
class DLList {
private:
typedef DLList<Element, GetLink> List;
typedef DLListLink<Element> Link;
public:
class Iterator {
public:
Iterator(List *list)
: fList(list),
fCurrent(NULL),
fNext(fList->GetFirst())
{
}
Iterator(const Iterator &other)
{
*this = other;
}
bool HasNext() const
{
return fNext;
}
Element *Next()
{
fCurrent = fNext;
if (fNext)
fNext = fList->GetNext(fNext);
return fCurrent;
}
Element *Remove()
{
Element *element = fCurrent;
if (fCurrent) {
fList->Remove(fCurrent);
fCurrent = NULL;
}
return element;
}
Iterator &operator=(const Iterator &other)
{
fList = other.fList;
fCurrent = other.fCurrent;
fNext = other.fNext;
return *this;
}
private:
List *fList;
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:
DLList() : fFirst(NULL), fLast(NULL) {}
DLList(const GetLink &getLink)
: fFirst(NULL), fLast(NULL), fGetLink(getLink) {}
~DLList() {}
inline bool IsEmpty() const { return (fFirst == NULL); }
inline void Insert(Element *element, bool back = true);
inline void Remove(Element *element);
inline void Swap(Element *a, Element *b);
inline void MoveFrom(DL_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 *GetPrevious(Element *element) const;
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:
Element *fFirst;
Element *fLast;
GetLink fGetLink;
};
} // namespace UserlandFSUtil
using UserlandFSUtil::DLList;
using UserlandFSUtil::DLListLink;
using UserlandFSUtil::DLListLinkImpl;
// inline methods
// Insert
DL_LIST_TEMPLATE_LIST
void
DL_LIST_CLASS_NAME::Insert(Element *element, bool back)
{
if (element) {
if (back) {
// append
Link *elLink = fGetLink(element);
elLink->previous = fLast;
elLink->next = NULL;
if (fLast)
fGetLink(fLast)->next = element;
else
fFirst = element;
fLast = element;
} else {
// prepend
Link *elLink = fGetLink(element);
elLink->previous = NULL;
elLink->next = fFirst;
if (fFirst)
fGetLink(fFirst)->previous = element;
else
fLast = element;
fFirst = element;
}
}
}
// Remove
DL_LIST_TEMPLATE_LIST
void
DL_LIST_CLASS_NAME::Remove(Element *element)
{
if (element) {
Link *elLink = fGetLink(element);
if (elLink->previous)
fGetLink(elLink->previous)->next = elLink->next;
else
fFirst = elLink->next;
if (elLink->next)
fGetLink(elLink->next)->previous = elLink->previous;
else
fLast = elLink->previous;
elLink->previous = NULL;
elLink->next = NULL;
}
}
// Swap
DL_LIST_TEMPLATE_LIST
void
DL_LIST_CLASS_NAME::Swap(Element *a, Element *b)
{
if (a && b && a != b) {
Link *aLink = fGetLink(a);
Link *bLink = fGetLink(b);
Element *aPrev = aLink->previous;
Element *bPrev = bLink->previous;
Element *aNext = aLink->next;
Element *bNext = bLink->next;
// place a
if (bPrev)
fGetLink(bPrev)->next = a;
else
fFirst = a;
if (bNext)
fGetLink(bNext)->previous = a;
else
fLast = a;
aLink->previous = bPrev;
aLink->next = bNext;
// place b
if (aPrev)
fGetLink(aPrev)->next = b;
else
fFirst = b;
if (aNext)
fGetLink(aNext)->previous = b;
else
fLast = b;
bLink->previous = aPrev;
bLink->next = aNext;
}
}
// MoveFrom
DL_LIST_TEMPLATE_LIST
void
DL_LIST_CLASS_NAME::MoveFrom(DL_LIST_CLASS_NAME *fromList)
{
if (fromList && fromList->fFirst) {
if (fFirst) {
fGetLink(fLast)->next = fromList->fFirst;
fGetLink(fFirst)->previous = fLast;
fLast = fromList->fLast;
} else {
fFirst = fromList->fFirst;
fLast = fromList->fLast;
}
fromList->fFirst = NULL;
fromList->fLast = NULL;
}
}
// RemoveAll
DL_LIST_TEMPLATE_LIST
void
DL_LIST_CLASS_NAME::RemoveAll()
{
Element *element = fFirst;
while (element) {
Link *elLink = fGetLink(element);
element = elLink->next;
elLink->previous = NULL;
elLink->next = NULL;
}
fFirst = NULL;
fLast = NULL;
}
// GetPrevious
DL_LIST_TEMPLATE_LIST
Element *
DL_LIST_CLASS_NAME::GetPrevious(Element *element) const
{
Element *result = NULL;
if (element)
result = fGetLink(element)->previous;
return result;
}
// GetNext
DL_LIST_TEMPLATE_LIST
Element *
DL_LIST_CLASS_NAME::GetNext(Element *element) const
{
Element *result = NULL;
if (element)
result = fGetLink(element)->next;
return result;
}
// Size
DL_LIST_TEMPLATE_LIST
int32
DL_LIST_CLASS_NAME::Size() const
{
int32 count = 0;
for (Element* element = GetFirst(); element; element = GetNext(element))
count++;
return count;
}
#endif // DL_LIST_H
+140
View File
@@ -0,0 +1,140 @@
#ifndef DEBUG_H
#define DEBUG_H
/* Debug - debug stuff
**
** Initial version by Axel Dörfler, [email protected]
** This file may be used under the terms of the OpenBeOS License.
*/
#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 "debug"
#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
#if __MWERKS__
# define __FUNCTION__ ""
#endif
#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, __FUNCTION__); x; dbg_printf_end(); }
#define DEBUG_CONTEXT_LINE(x) { dbg_printf_begin(); __out(DEBUG_APP " [%Ld: %5ld] %s():%d: ", system_time(), DEBUG_THREAD, __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_H */
@@ -0,0 +1,130 @@
// DriverSettings.h
#ifndef USERLAND_FS_DRIVER_SETTINGS_H
#define USERLAND_FS_DRIVER_SETTINGS_H
struct driver_parameter;
struct driver_settings;
namespace UserlandFSUtil {
class DriverParameter;
class DriverParameterContainer;
// DriverParameterIterator
class DriverParameterIterator {
public:
DriverParameterIterator();
DriverParameterIterator(
const DriverParameterIterator& other);
~DriverParameterIterator();
bool HasNext() const;
bool GetNext(DriverParameter* parameter);
DriverParameterIterator& operator=(
const DriverParameterIterator& other);
private:
friend class DriverParameterContainer;
class Delegate;
DriverParameterIterator(Delegate* delegate);
void _SetTo(Delegate* delegate, bool addReference);
Delegate* fDelegate;
};
// DriverParameterContainer
class DriverParameterContainer {
public:
DriverParameterContainer();
virtual ~DriverParameterContainer();
int32 CountParameters() const;
const driver_parameter* GetParameters() const;
bool GetParameterAt(int32 index,
DriverParameter* parameter) const;
bool FindParameter(const char* name,
DriverParameter* parameter) const;
DriverParameterIterator GetParameterIterator() const;
DriverParameterIterator GetParameterIterator(
const char* name) const;
const char* GetParameterValue(const char* name,
const char* unknownValue = NULL,
const char* noValue = NULL) const;
bool GetBoolParameterValue(const char* name,
bool unknownValue = false,
bool noValue = false) const;
int32 GetInt32ParameterValue(const char* name,
int32 unknownValue = 0,
int32 noValue = 0) const;
int64 GetInt64ParameterValue(const char* name,
int64 unknownValue = 0,
int64 noValue = 0) const;
protected:
virtual const driver_parameter*
GetParametersAndCount(int32* count) const = 0;
private:
class Iterator;
class NameIterator;
};
// DriverSettings
class DriverSettings : public DriverParameterContainer {
public:
DriverSettings();
virtual ~DriverSettings();
status_t Load(const char* driverName);
void Unset();
protected:
virtual const driver_parameter*
GetParametersAndCount(int32* count) const;
private:
void* fSettingsHandle;
const driver_settings* fSettings;
};
// DriverParameter
class DriverParameter : public DriverParameterContainer {
public:
DriverParameter();
virtual ~DriverParameter();
void SetTo(const driver_parameter* parameter);
const char* GetName() const;
int32 CountValues() const;
const char* const* GetValues() const;
const char* ValueAt(int32 index,
const char* noValue = NULL) const;
bool BoolValueAt(int32 index,
bool noValue = false) const;
int32 Int32ValueAt(int32 index,
int32 noValue = 0) const;
int64 Int64ValueAt(int32 index,
int64 noValue = 0) const;
protected:
virtual const driver_parameter*
GetParametersAndCount(int32* count) const;
private:
const driver_parameter* fParameter;
};
} // namespace UserlandFSUtil
using UserlandFSUtil::DriverParameterIterator;
using UserlandFSUtil::DriverParameterContainer;
using UserlandFSUtil::DriverSettings;
using UserlandFSUtil::DriverParameter;
#endif // USERLAND_FS_DRIVER_SETTINGS_H
+444
View File
@@ -0,0 +1,444 @@
// HashMap.h
//
// Copyright (c) 2004, Ingo Weinhold ([email protected])
//
// 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 HASH_MAP_H
#define HASH_MAP_H
//#include <Debug.h>
#include "AutoLocker.h"
#include "Locker.h"
#include "OpenHashTable.h"
// HashMapElement
template<typename Key, typename Value>
class HashMapElement : public OpenHashElement {
private:
typedef HashMapElement<Key, Value> Element;
public:
HashMapElement() : OpenHashElement(), fKey(), fValue()
{
fNext = -1;
}
inline uint32 Hash() const
{
return fKey.GetHashCode();
}
inline bool operator==(const OpenHashElement &_element) const
{
const Element &element = static_cast<const Element&>(_element);
return (fKey == element.fKey);
}
inline void Adopt(Element &element)
{
fKey = element.fKey;
fValue = element.fValue;
}
Key fKey;
Value fValue;
};
// HashMap
template<typename Key, typename Value>
class HashMap {
public:
class Entry {
public:
Entry() {}
Entry(const Key& key, Value value) : key(key), value(value) {}
Key key;
Value value;
};
class Iterator {
private:
typedef HashMapElement<Key, Value> Element;
public:
Iterator(const Iterator& other)
: fMap(other.fMap),
fIndex(other.fIndex),
fElement(other.fElement),
fLastElement(other.fElement)
{
}
bool HasNext() const
{
return fElement;
}
Entry Next()
{
if (!fElement)
return Entry();
Entry result(fElement->fKey, fElement->fValue);
_FindNext();
return result;
}
Entry Remove()
{
if (!fLastElement)
return Entry();
Entry result(fLastElement->fKey, fLastElement->fValue);
fMap->fTable.Remove(fLastElement, true);
fLastElement = NULL;
return result;
}
Iterator& operator=(const Iterator& other)
{
fMap = other.fMap;
fIndex = other.fIndex;
fElement = other.fElement;
fLastElement = other.fLastElement;
return *this;
}
private:
Iterator(HashMap<Key, Value>* map)
: fMap(map),
fIndex(0),
fElement(NULL),
fLastElement(NULL)
{
// find first
_FindNext();
}
void _FindNext()
{
fLastElement = fElement;
if (fElement && fElement->fNext >= 0) {
fElement = fMap->fTable.ElementAt(fElement->fNext);
return;
}
fElement = NULL;
int32 arraySize = fMap->fTable.ArraySize();
for (; !fElement && fIndex < arraySize; fIndex++)
fElement = fMap->fTable.FindFirst(fIndex);
}
private:
friend class HashMap<Key, Value>;
HashMap<Key, Value>* fMap;
int32 fIndex;
Element* fElement;
Element* fLastElement;
};
HashMap();
~HashMap();
status_t InitCheck() const;
status_t Put(const Key& key, Value value);
Value Remove(const Key& key);
void Clear();
Value Get(const Key& key) const;
bool ContainsKey(const Key& key) const;
int32 Size() const;
Iterator GetIterator();
protected:
typedef HashMapElement<Key, Value> Element;
friend class Iterator;
private:
Element *_FindElement(const Key& key) const;
protected:
OpenHashElementArray<Element> fElementArray;
OpenHashTable<Element, OpenHashElementArray<Element> > fTable;
};
// SynchronizedHashMap
template<typename Key, typename Value>
class SynchronizedHashMap : public Locker {
public:
typedef HashMap<Key, Value>::Entry Entry;
typedef HashMap<Key, Value>::Iterator Iterator;
SynchronizedHashMap() : Locker("synchronized hash map") {}
~SynchronizedHashMap() { Lock(); }
status_t InitCheck() const
{
return fMap.InitCheck();
}
status_t Put(const Key& key, Value value)
{
MapLocker locker(this);
if (!locker.IsLocked())
return B_ERROR;
return fMap.Put(key, value);
}
Value Remove(const Key& key)
{
MapLocker locker(this);
if (!locker.IsLocked())
return Value();
return fMap.Remove(key);
}
void Clear()
{
MapLocker locker(this);
return fMap.Clear();
}
Value Get(const Key& key) const
{
const Locker* lock = this;
MapLocker locker(const_cast<Locker*>(lock));
if (!locker.IsLocked())
return Value();
return fMap.Get(key);
}
bool ContainsKey(const Key& key) const
{
const Locker* lock = this;
MapLocker locker(const_cast<Locker*>(lock));
if (!locker.IsLocked())
return false;
return fMap.ContainsKey(key);
}
int32 Size() const
{
const Locker* lock = this;
MapLocker locker(const_cast<Locker*>(lock));
return fMap.Size();
}
Iterator GetIterator()
{
return fMap.GetIterator();
}
// for debugging only
const HashMap<Key, Value>& GetUnsynchronizedMap() const { return fMap; }
HashMap<Key, Value>& GetUnsynchronizedMap() { return fMap; }
protected:
typedef AutoLocker<Locker> MapLocker;
HashMap<Key, Value> fMap;
};
// HashKey32
template<typename Value>
struct HashKey32 {
HashKey32() {}
HashKey32(const Value& value) : value(value) {}
uint32 GetHashCode() const
{
return (uint32)value;
}
HashKey32<Value> operator=(const HashKey32<Value>& other)
{
value = other.value;
return *this;
}
bool operator==(const HashKey32<Value>& other) const
{
return (value == other.value);
}
bool operator!=(const HashKey32<Value>& other) const
{
return (value != other.value);
}
Value value;
};
// HashKey64
template<typename Value>
struct HashKey64 {
HashKey64() {}
HashKey64(const Value& value) : value(value) {}
uint32 GetHashCode() const
{
uint64 v = (uint64)value;
return (uint32)(v >> 32) ^ (uint32)v;
}
HashKey64<Value> operator=(const HashKey64<Value>& other)
{
value = other.value;
return *this;
}
bool operator==(const HashKey64<Value>& other) const
{
return (value == other.value);
}
bool operator!=(const HashKey64<Value>& other) const
{
return (value != other.value);
}
Value value;
};
// HashMap
// constructor
template<typename Key, typename Value>
HashMap<Key, Value>::HashMap()
: fElementArray(1000),
fTable(1000, &fElementArray)
{
}
// destructor
template<typename Key, typename Value>
HashMap<Key, Value>::~HashMap()
{
}
// InitCheck
template<typename Key, typename Value>
status_t
HashMap<Key, Value>::InitCheck() const
{
return (fTable.InitCheck() && fElementArray.InitCheck()
? B_OK : B_NO_MEMORY);
}
// Put
template<typename Key, typename Value>
status_t
HashMap<Key, Value>::Put(const Key& key, Value value)
{
Element* element = _FindElement(key);
if (element) {
// already contains the key: just set the new value
element->fValue = value;
return B_OK;
}
// does not contain the key yet: add an element
element = fTable.Add(key.GetHashCode());
if (!element)
return B_NO_MEMORY;
element->fKey = key;
element->fValue = value;
return B_OK;
}
// Remove
template<typename Key, typename Value>
Value
HashMap<Key, Value>::Remove(const Key& key)
{
Value value = Value();
if (Element* element = _FindElement(key)) {
value = element->fValue;
fTable.Remove(element);
}
return value;
}
// Clear
template<typename Key, typename Value>
void
HashMap<Key, Value>::Clear()
{
fTable.RemoveAll();
}
// Get
template<typename Key, typename Value>
Value
HashMap<Key, Value>::Get(const Key& key) const
{
if (Element* element = _FindElement(key))
return element->fValue;
return Value();
}
// ContainsKey
template<typename Key, typename Value>
bool
HashMap<Key, Value>::ContainsKey(const Key& key) const
{
return _FindElement(key);
}
// Size
template<typename Key, typename Value>
int32
HashMap<Key, Value>::Size() const
{
return fTable.CountElements();
}
// GetIterator
template<typename Key, typename Value>
HashMap<Key, Value>::Iterator
HashMap<Key, Value>::GetIterator()
{
return Iterator(this);
}
// _FindElement
template<typename Key, typename Value>
HashMap<Key, Value>::Element *
HashMap<Key, Value>::_FindElement(const Key& key) const
{
Element* element = fTable.FindFirst(key.GetHashCode());
while (element && element->fKey != key) {
if (element->fNext >= 0)
element = fTable.ElementAt(element->fNext);
else
element = NULL;
}
return element;
}
#endif // HASH_MAP_H
+323
View File
@@ -0,0 +1,323 @@
// HashSet.h
//
// Copyright (c) 2004, Ingo Weinhold ([email protected])
//
// 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 HASH_SET_H
#define HASH_SET_H
#include "AutoLocker.h"
#include "Locker.h"
#include "OpenHashTable.h"
// HashSetElement
template<typename Key>
class HashSetElement : public OpenHashElement {
private:
typedef HashSetElement<Key> Element;
public:
HashSetElement() : OpenHashElement(), fKey()
{
fNext = -1;
}
inline uint32 Hash() const
{
return fKey.GetHashCode();
}
inline bool operator==(const OpenHashElement &_element) const
{
const Element &element = static_cast<const Element&>(_element);
return (fKey == element.fKey);
}
inline void Adopt(Element &element)
{
fKey = element.fKey;
}
Key fKey;
};
// HashSet
template<typename Key>
class HashSet {
public:
class Iterator {
private:
typedef HashSetElement<Key> Element;
public:
Iterator(const Iterator& other)
: fSet(other.fSet),
fIndex(other.fIndex),
fElement(other.fElement),
fLastElement(other.fElement)
{
}
bool HasNext() const
{
return fElement;
}
Key Next()
{
if (!fElement)
return Key();
Key result(fElement->fKey);
_FindNext();
return result;
}
bool Remove()
{
if (!fLastElement)
return false;
fSet->fTable.Remove(fLastElement);
fLastElement = NULL;
return true;
}
Iterator& operator=(const Iterator& other)
{
fSet = other.fSet;
fIndex = other.fIndex;
fElement = other.fElement;
fLastElement = other.fLastElement;
return *this;
}
private:
Iterator(HashSet<Key>* map)
: fSet(map),
fIndex(0),
fElement(NULL),
fLastElement(NULL)
{
// find first
_FindNext();
}
void _FindNext()
{
fLastElement = fElement;
if (fElement && fElement->fNext >= 0) {
fElement = fSet->fTable.ElementAt(fElement->fNext);
return;
}
fElement = NULL;
int32 arraySize = fSet->fTable.ArraySize();
for (; !fElement && fIndex < arraySize; fIndex++)
fElement = fSet->fTable.FindFirst(fIndex);
}
private:
friend class HashSet<Key>;
HashSet<Key>* fSet;
int32 fIndex;
Element* fElement;
Element* fLastElement;
};
HashSet();
~HashSet();
status_t InitCheck() const;
status_t Add(const Key& key);
bool Remove(const Key& key);
bool Contains(const Key& key) const;
int32 Size() const;
Iterator GetIterator();
protected:
typedef HashSetElement<Key> Element;
friend class Iterator;
private:
Element *_FindElement(const Key& key) const;
protected:
OpenHashElementArray<Element> fElementArray;
OpenHashTable<Element, OpenHashElementArray<Element> > fTable;
};
// SynchronizedHashSet
template<typename Key>
class SynchronizedHashSet : public Locker {
public:
typedef HashSet<Key>::Iterator Iterator;
SynchronizedHashSet() : Locker("synchronized hash map") {}
~SynchronizedHashSet() { Lock(); }
status_t InitCheck() const
{
return fSet.InitCheck();
}
status_t Add(const Key& key)
{
MapLocker locker(this);
if (!locker.IsLocked())
return B_ERROR;
return fSet.Add(key);
}
bool Remove(const Key& key)
{
MapLocker locker(this);
if (!locker.IsLocked())
return false;
return fSet.Remove(key);
}
bool Contains(const Key& key) const
{
const Locker* lock = this;
MapLocker locker(const_cast<Locker*>(lock));
if (!locker.IsLocked())
return false;
return fSet.Contains(key);
}
int32 Size() const
{
const Locker* lock = this;
MapLocker locker(const_cast<Locker*>(lock));
return fSet.Size();
}
Iterator GetIterator()
{
return fSet.GetIterator();
}
// for debugging only
const HashSet<Key>& GetUnsynchronizedSet() const { return fSet; }
HashSet<Key>& GetUnsynchronizedSet() { return fSet; }
protected:
typedef AutoLocker<Locker> MapLocker;
HashSet<Key> fSet;
};
// HashSet
// constructor
template<typename Key>
HashSet<Key>::HashSet()
: fElementArray(1000),
fTable(1000, &fElementArray)
{
}
// destructor
template<typename Key>
HashSet<Key>::~HashSet()
{
}
// InitCheck
template<typename Key>
status_t
HashSet<Key>::InitCheck() const
{
return (fTable.InitCheck() && fElementArray.InitCheck()
? B_OK : B_NO_MEMORY);
}
// Add
template<typename Key>
status_t
HashSet<Key>::Add(const Key& key)
{
if (Contains(key))
return B_OK;
Element* element = fTable.Add(key.GetHashCode());
if (!element)
return B_NO_MEMORY;
element->fKey = key;
return B_OK;
}
// Remove
template<typename Key>
bool
HashSet<Key>::Remove(const Key& key)
{
if (Element* element = _FindElement(key)) {
fTable.Remove(element);
return true;
}
return false;
}
// Contains
template<typename Key>
bool
HashSet<Key>::Contains(const Key& key) const
{
return _FindElement(key);
}
// Size
template<typename Key>
int32
HashSet<Key>::Size() const
{
return fTable.CountElements();
}
// GetIterator
template<typename Key>
HashSet<Key>::Iterator
HashSet<Key>::GetIterator()
{
return Iterator(this);
}
// _FindElement
template<typename Key>
HashSet<Key>::Element *
HashSet<Key>::_FindElement(const Key& key) const
{
Element* element = fTable.FindFirst(key.GetHashCode());
while (element && element->fKey != key) {
if (element->fNext >= 0)
element = fTable.ElementAt(element->fNext);
else
element = NULL;
}
return element;
}
#endif // HASH_SET_H
@@ -0,0 +1,31 @@
// LazyInitializable.h
#ifndef USERLAND_FS_LAZY_INITIALIZABLE_H
#define USERLAND_FS_LAZY_INITIALIZABLE_H
#include <OS.h>
namespace UserlandFSUtil {
class LazyInitializable {
public:
LazyInitializable();
LazyInitializable(bool init);
virtual ~LazyInitializable();
status_t Access();
status_t InitCheck() const;
protected:
virtual status_t FirstTimeInit() = 0;
protected:
status_t fInitStatus;
sem_id fInitSemaphore;
};
} // namespace UserlandFSUtil
using UserlandFSUtil::LazyInitializable;
#endif // USERLAND_FS_LAZY_INITIALIZABLE_H
@@ -0,0 +1,59 @@
//
// $Id: Locker.h,v 1.1 2002/07/09 12:24:33 ejakowatz Exp $
//
// This is the Locker interface for OpenBeOS. It has been created to
// be source and binary compatible with the BeOS version of Locker.
//
// bonefish:
// * Removed `virtual' from destructor and FBC reserved space.
// * Renamed to Locker.
#ifndef _OPENBEOS_LOCKER_H
#define _OPENBEOS_LOCKER_H
#include <OS.h>
#include <SupportDefs.h>
namespace UserlandFSUtil {
class Locker {
public:
Locker();
Locker(const char *name);
Locker(bool benaphore_style);
Locker(const char *name, bool benaphore_style);
// The following constructor is not documented in the BeBook
// and is only listed here to ensure binary compatibility.
// DO NOT USE THIS CONSTRUCTOR!
Locker(const char *name, bool benaphore_style, bool);
~Locker();
bool Lock(void);
status_t LockWithTimeout(bigtime_t timeout);
void Unlock(void);
thread_id LockingThread(void) const;
bool IsLocked(void) const;
int32 CountLocks(void) const;
int32 CountLockRequests(void) const;
sem_id Sem(void) const;
private:
void InitLocker(const char *name, bool benaphore_style);
bool AcquireLock(bigtime_t timeout, status_t *error);
int32 fBenaphoreCount;
sem_id fSemaphoreID;
thread_id fLockOwner;
int32 fRecursiveCount;
};
} // namespace UserlandFSUtil
using UserlandFSUtil::Locker;
#endif // _OPENBEOS_LOCKER_H
@@ -0,0 +1,80 @@
// ObjectTracker.h
#ifndef USERLAND_FS_OBJECT_TRACKER_H
#define USERLAND_FS_OBJECT_TRACKER_H
#include "DLList.h"
#include "Locker.h"
namespace UserlandFSUtil {
class ObjectTracker;
class GetObjectTrackableLink;
// ObjectTrackable
class ObjectTrackable {
public:
ObjectTrackable();
virtual ~ObjectTrackable();
private:
friend class ObjectTracker;
friend class GetObjectTrackableLink;
DLListLink<ObjectTrackable> fLink;
};
// GetObjectTrackableLink
struct GetObjectTrackableLink {
inline DLListLink<ObjectTrackable> *operator()(
ObjectTrackable* trackable) const
{
return &trackable->fLink;
}
inline const DLListLink<ObjectTrackable> *operator()(
const ObjectTrackable* trackable) const
{
return &trackable->fLink;
}
};
// ObjectTracker
class ObjectTracker {
private:
ObjectTracker();
~ObjectTracker();
public:
static ObjectTracker* InitDefault();
static void ExitDefault();
static ObjectTracker* GetDefault();
private:
friend class ObjectTrackable;
void AddTrackable(ObjectTrackable* trackable);
void RemoveTrackable(ObjectTrackable* trackable);
private:
Locker fLock;
DLList<ObjectTrackable, GetObjectTrackableLink> fTrackables;
static ObjectTracker* sTracker;
};
} // namespace UserlandFSUtil
using UserlandFSUtil::ObjectTrackable;
using UserlandFSUtil::ObjectTracker;
#ifdef DEBUG_OBJECT_TRACKING
# define ONLY_OBJECT_TRACKABLE_BASE_CLASS : private ObjectTrackable
# define FIRST_OBJECT_TRACKABLE_BASE_CLASS private ObjectTrackable,
#else
# define ONLY_OBJECT_TRACKABLE_BASE_CLASS
# define FIRST_OBJECT_TRACKABLE_BASE_CLASS
#endif
#endif // USERLAND_FS_OBJECT_TRACKER_H
@@ -0,0 +1,510 @@
/*
Open Tracker License
Terms and Conditions
Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
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 applies to all licensees
and 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 TITLE, MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BE INCORPORATED 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 Be Incorporated shall not be
used in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from Be Incorporated.
Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
of Be Incorporated in the United States and other countries. Other brand product
names are registered trademarks or trademarks of their respective holders.
All rights reserved.
*/
// bonefish:
// * removed need for exceptions
// * fixed warnings
// * implemented rehashing
// * added RemoveAll()
// TODO:
// * shrinking of element vectors
// Hash table with open addresssing
#ifndef __OPEN_HASH_TABLE__
#define __OPEN_HASH_TABLE__
#include <malloc.h>
#include <new.h>
// don't include <Debug.h>
#define ASSERT(E) (void)0
#define TRESPASS() (void)0
//namespace BPrivate {
template <class Element>
class ElementVector {
// element vector for OpenHashTable needs to implement this
// interface
public:
Element &At(int32 index);
Element *Add();
int32 IndexOf(const Element &) const;
void Remove(int32 index);
};
class OpenHashElement {
public:
uint32 Hash() const;
bool operator==(const OpenHashElement &) const;
void Adopt(OpenHashElement &);
// low overhead copy, original element is in undefined state
// after call (calls Adopt on BString members, etc.)
int32 fNext;
};
const uint32 kPrimes [] = {
509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
134217689, 268435399, 536870909, 1073741789, 2147483647, 0
};
template <class Element, class ElementVec = ElementVector<Element> >
class OpenHashTable {
public:
OpenHashTable(int32 minSize, ElementVec *elementVector = 0,
float maxLoadFactor = 0.8);
// it is up to the subclass of OpenHashTable to supply
// elementVector
~OpenHashTable();
bool InitCheck() const;
void SetElementVector(ElementVec *elementVector);
Element *FindFirst(uint32 elementHash) const;
Element *Add(uint32 elementHash);
void Remove(Element *element, bool dontRehash = false);
void RemoveAll();
// when calling Add, any outstanding element pointer may become
// invalid; to deal with this, get the element index and restore
// it after the add
int32 ElementIndex(const Element *) const;
Element *ElementAt(int32 index) const;
int32 ArraySize() const;
int32 VectorSize() const;
int32 CountElements() const;
protected:
static int32 OptimalSize(int32 minSize);
private:
bool _RehashIfNeeded();
bool _Rehash();
int32 fArraySize;
int32 fInitialSize;
int32 fElementCount;
int32 *fHashArray;
ElementVec *fElementVector;
float fMaxLoadFactor;
};
template <class Element>
class OpenHashElementArray : public ElementVector<Element> {
// this is a straightforward implementation of an element vector
// deleting is handled by linking deleted elements into a free list
// the vector never shrinks
public:
OpenHashElementArray(int32 initialSize);
~OpenHashElementArray();
bool InitCheck() const;
Element &At(int32 index);
const Element &At(int32 index) const;
Element *Add(const Element &);
Element *Add();
void Remove(int32 index);
int32 IndexOf(const Element &) const;
int32 Size() const;
private:
Element *fData;
int32 fSize;
int32 fNextFree;
int32 fNextDeleted;
};
//-----------------------------------
template<class Element, class ElementVec>
OpenHashTable<Element, ElementVec>::OpenHashTable(int32 minSize,
ElementVec *elementVector, float maxLoadFactor)
: fArraySize(OptimalSize(minSize)),
fInitialSize(fArraySize),
fElementCount(0),
fElementVector(elementVector),
fMaxLoadFactor(maxLoadFactor)
{
// sanity check the maximal load factor
if (fMaxLoadFactor < 0.5)
fMaxLoadFactor = 0.5;
// allocate and init the array
fHashArray = (int32*)calloc(fArraySize, sizeof(int32));
if (fHashArray) {
for (int32 index = 0; index < fArraySize; index++)
fHashArray[index] = -1;
}
}
template<class Element, class ElementVec>
OpenHashTable<Element, ElementVec>::~OpenHashTable()
{
RemoveAll();
free(fHashArray);
}
template<class Element, class ElementVec>
bool
OpenHashTable<Element, ElementVec>::InitCheck() const
{
return (fHashArray && fElementVector);
}
template<class Element, class ElementVec>
int32
OpenHashTable<Element, ElementVec>::OptimalSize(int32 minSize)
{
for (int32 index = 0; ; index++)
if (!kPrimes[index] || kPrimes[index] >= (uint32)minSize)
return (int32)kPrimes[index];
return 0;
}
template<class Element, class ElementVec>
Element *
OpenHashTable<Element, ElementVec>::FindFirst(uint32 hash) const
{
ASSERT(fElementVector);
hash %= fArraySize;
if (fHashArray[hash] < 0)
return 0;
return &fElementVector->At(fHashArray[hash]);
}
template<class Element, class ElementVec>
int32
OpenHashTable<Element, ElementVec>::ElementIndex(const Element *element) const
{
return fElementVector->IndexOf(*element);
}
template<class Element, class ElementVec>
Element *
OpenHashTable<Element, ElementVec>::ElementAt(int32 index) const
{
return &fElementVector->At(index);
}
template<class Element, class ElementVec>
int32
OpenHashTable<Element, ElementVec>::ArraySize() const
{
return fArraySize;
}
template<class Element, class ElementVec>
int32
OpenHashTable<Element, ElementVec>::VectorSize() const
{
return fElementVector->Size();
}
template<class Element, class ElementVec>
int32
OpenHashTable<Element, ElementVec>::CountElements() const
{
return fElementCount;
}
template<class Element, class ElementVec>
Element *
OpenHashTable<Element, ElementVec>::Add(uint32 hash)
{
ASSERT(fElementVector);
_RehashIfNeeded();
hash %= fArraySize;
Element *result = fElementVector->Add();
if (result) {
result->fNext = fHashArray[hash];
fHashArray[hash] = fElementVector->IndexOf(*result);
fElementCount++;
}
return result;
}
template<class Element, class ElementVec>
void
OpenHashTable<Element, ElementVec>::Remove(Element *element, bool dontRehash)
{
if (!dontRehash)
_RehashIfNeeded();
uint32 hash = element->Hash() % fArraySize;
int32 next = fHashArray[hash];
ASSERT(next >= 0);
if (&fElementVector->At(next) == element) {
fHashArray[hash] = element->fNext;
fElementVector->Remove(next);
fElementCount--;
return;
}
for (int32 index = next; index >= 0; ) {
// look for an existing match in table
next = fElementVector->At(index).fNext;
if (next < 0) {
TRESPASS();
return;
}
if (&fElementVector->At(next) == element) {
fElementVector->At(index).fNext = element->fNext;
fElementVector->Remove(next);
fElementCount--;
return;
}
index = next;
}
}
template<class Element, class ElementVec>
void
OpenHashTable<Element, ElementVec>::RemoveAll()
{
for (int32 i = 0; fElementCount > 0 && i < fArraySize; i++) {
int32 index = fHashArray[i];
while (index >= 0) {
Element* element = &fElementVector->At(index);
int32 next = element->fNext;
fElementVector->Remove(index);
fElementCount--;
index = next;
}
fHashArray[i] = -1;
}
_RehashIfNeeded();
}
template<class Element, class ElementVec>
void
OpenHashTable<Element, ElementVec>::SetElementVector(ElementVec *elementVector)
{
fElementVector = elementVector;
}
// _RehashIfNeeded
template<class Element, class ElementVec>
bool
OpenHashTable<Element, ElementVec>::_RehashIfNeeded()
{
// The load factor range [fMaxLoadFactor / 3, fMaxLoadFactor] is fine,
// I think. After rehashing the load factor will be about
// fMaxLoadFactor * 2 / 3, respectively fMaxLoadFactor / 2.
float loadFactor = (float)fElementCount / (float)fArraySize;
if (loadFactor > fMaxLoadFactor
|| (fArraySize > fInitialSize && loadFactor < fMaxLoadFactor / 3)) {
return _Rehash();
}
return true;
}
// _Rehash
template<class Element, class ElementVec>
bool
OpenHashTable<Element, ElementVec>::_Rehash()
{
bool result = true;
int32 newSize = int32(fElementCount * 1.73 * fMaxLoadFactor);
newSize = (fInitialSize > newSize ? fInitialSize : newSize);
if (newSize != fArraySize) {
// allocate a new array
int32 *newHashArray = (int32*)calloc(newSize, sizeof(int32));
if (newHashArray) {
// init the new hash array
for (int32 index = 0; index < newSize; index++)
newHashArray[index] = -1;
// iterate through all elements and put them into the new
// hash array
for (int i = 0; i < fArraySize; i++) {
int32 index = fHashArray[i];
while (index >= 0) {
// insert the element in the new array
Element &element = fElementVector->At(index);
int32 next = element.fNext;
uint32 hash = (element.Hash() % newSize);
element.fNext = newHashArray[hash];
newHashArray[hash] = index;
// next element in old list
index = next;
}
}
// delete the old array and set the new one
free(fHashArray);
fHashArray = newHashArray;
fArraySize = newSize;
} else
result = false;
}
return result;
}
template<class Element>
OpenHashElementArray<Element>::OpenHashElementArray(int32 initialSize)
: fSize(initialSize),
fNextFree(0),
fNextDeleted(-1)
{
fData = (Element*)calloc((size_t)initialSize, sizeof(Element));
}
template<class Element>
OpenHashElementArray<Element>::~OpenHashElementArray()
{
free(fData);
}
template<class Element>
bool
OpenHashElementArray<Element>::InitCheck() const
{
return fData;
}
template<class Element>
Element &
OpenHashElementArray<Element>::At(int32 index)
{
ASSERT(index < fSize);
return fData[index];
}
template<class Element>
const Element &
OpenHashElementArray<Element>::At(int32 index) const
{
ASSERT(index < fSize);
return fData[index];
}
template<class Element>
int32
OpenHashElementArray<Element>::IndexOf(const Element &element) const
{
int32 result = &element - fData;
if (result < 0 || result > fSize)
return -1;
return result;
}
template<class Element>
int32
OpenHashElementArray<Element>::Size() const
{
return fSize;
}
template<class Element>
Element *
OpenHashElementArray<Element>::Add(const Element &newElement)
{
Element *element = Add();
if (element)
element.Adopt(newElement);
return element;
}
#if DEBUG
const int32 kGrowChunk = 10;
#else
const int32 kGrowChunk = 1024;
#endif
template<class Element>
Element *
OpenHashElementArray<Element>::Add()
{
int32 index = fNextFree;
if (fNextDeleted >= 0) {
index = fNextDeleted;
fNextDeleted = At(index).fNext;
} else if (fNextFree >= fSize - 1) {
int32 newSize = fSize + kGrowChunk;
/*
Element *newData = (Element *)calloc((size_t)newSize , sizeof(Element));
if (!newData)
return NULL;
memcpy(newData, fData, fSize * sizeof(Element));
free(fData);
*/
Element *newData = (Element*)realloc(fData,
(size_t)newSize * sizeof(Element));
if (!newData)
return NULL;
fData = newData;
fSize = newSize;
index = fNextFree;
fNextFree++;
} else
fNextFree++;
new (&At(index)) Element;
// call placement new to initialize the element properly
ASSERT(At(index).fNext == -1);
return &At(index);
}
template<class Element>
void
OpenHashElementArray<Element>::Remove(int32 index)
{
// delete by chaining empty elements in a single linked
// list, reusing the next field
ASSERT(index < fSize);
At(index).~Element();
// call the destructor explicitly to destroy the element
// properly
At(index).fNext = fNextDeleted;
fNextDeleted = index;
}
//} // namespace BPrivate
//using namespace BPrivate;
#endif
@@ -0,0 +1,118 @@
// Referencable.h
#ifndef USERLAND_FS_REFERENCABLE_H
#define USERLAND_FS_REFERENCABLE_H
#include <SupportDefs.h>
#include "ObjectTracker.h"
namespace UserlandFSUtil {
// Referencable
class Referencable ONLY_OBJECT_TRACKABLE_BASE_CLASS {
public:
Referencable(
bool deleteWhenUnreferenced = false);
virtual ~Referencable();
void AddReference();
bool RemoveReference(); // returns true after last
int32 CountReferences() const;
protected:
vint32 fReferenceCount;
bool fDeleteWhenUnreferenced;
};
// Reference
template<typename Type>
class Reference {
public:
Reference()
: fObject(NULL)
{
}
Reference(Type* object, bool alreadyHasReference = false)
: fObject(NULL)
{
SetTo(object, alreadyHasReference);
}
Reference(const Reference<Type>& other)
: fObject(NULL)
{
SetTo(other.fObject);
}
~Reference()
{
Unset();
}
void SetTo(Type* object, bool alreadyHasReference = false)
{
Unset();
fObject = object;
if (fObject && !alreadyHasReference)
fObject->AddReference();
}
void Unset()
{
if (fObject) {
fObject->RemoveReference();
fObject = NULL;
}
}
Type* Get() const
{
return fObject;
}
Type* Detach()
{
Type* object = fObject;
fObject = NULL;
return object;
}
Type& operator*() const
{
return *fObject;
}
Type* operator->() const
{
return fObject;
}
Reference& operator=(const Reference<Type>& other)
{
SetTo(other.fObject);
return *this;
}
bool operator==(const Reference<Type>& other) const
{
return (fObject == other.fObject);
}
bool operator!=(const Reference<Type>& other) const
{
return (fObject != other.fObject);
}
private:
Type* fObject;
};
} // namespace UserlandFSUtil
using UserlandFSUtil::Referencable;
using UserlandFSUtil::Reference;
#endif // USERLAND_FS_REFERENCABLE_H
+332
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
@@ -0,0 +1,70 @@
// String.h
#ifndef STRING_H
#define STRING_H
#include <string.h>
#include <SupportDefs.h>
// string_hash
//
// from the Dragon Book: a slightly modified hashpjw()
static inline
uint32
string_hash(const char *name)
{
uint32 h = 0;
if (name) {
for (; *name; name++) {
uint32 g = h & 0xf0000000;
if (g)
h ^= g >> 24;
h = (h << 4) + *name;
}
}
return h;
}
#ifdef __cplusplus
namespace UserlandFSUtil {
// String
class String {
public:
String();
String(const String &string);
String(const char *string, int32 length = -1);
~String();
bool SetTo(const char *string, int32 maxLength = -1);
void Unset();
void Truncate(int32 newLength);
const char *GetString() const;
int32 GetLength() const { return fLength; }
uint32 GetHashCode() const { return string_hash(GetString()); }
String &operator=(const String &string);
bool operator==(const String &string) const;
bool operator!=(const String &string) const { return !(*this == string); }
private:
bool _SetTo(const char *string, int32 length);
private:
int32 fLength;
char *fString;
};
} // namespace UserlandFSUtil
using UserlandFSUtil::String;
#endif // __cplusplus
#endif // STRING_H
+798
View File
@@ -0,0 +1,798 @@
// Vector.h
//
// Copyright (c) 2003, Ingo Weinhold ([email protected])
//
// 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 _VECTOR_H
#define _VECTOR_H
#include <new>
#include <stdlib.h>
#include <string.h>
#include <SupportDefs.h>
template<typename Value> class VectorIterator;
// for convenience
#define _VECTOR_TEMPLATE_LIST template<typename Value>
#define _VECTOR_CLASS_NAME Vector<Value>
/*!
\class Vector
\brief A generic vector implementation.
*/
template<typename Value>
class Vector {
public:
typedef VectorIterator<Value> Iterator;
typedef VectorIterator<const Value> ConstIterator;
private:
static const size_t kDefaultChunkSize = 10;
static const size_t kMaximalChunkSize = 1024 * 1024;
public:
Vector(size_t chunkSize = kDefaultChunkSize);
~Vector();
status_t PushFront(const Value &value);
status_t PushBack(const Value &value);
void PopFront();
void PopBack();
status_t Insert(const Value &value, int32 index);
status_t Insert(const Value &value, const Iterator &iterator);
int32 Remove(const Value &value);
Iterator Erase(int32 index);
Iterator Erase(const Iterator &iterator);
inline int32 Count() const;
inline bool IsEmpty() const;
void MakeEmpty();
inline Iterator Begin();
inline ConstIterator Begin() const;
inline Iterator End();
inline ConstIterator End() const;
inline Iterator Null();
inline ConstIterator Null() const;
inline Iterator IteratorForIndex(int32 index);
inline ConstIterator IteratorForIndex(int32 index) const;
inline const Value &ElementAt(int32 index) const;
inline Value &ElementAt(int32 index);
int32 IndexOf(const Value &value, int32 start = 0) const;
Iterator Find(const Value &value);
Iterator Find(const Value &value, const Iterator &start);
ConstIterator Find(const Value &value) const;
ConstIterator Find(const Value &value, const ConstIterator &start) const;
inline Value &operator[](int32 index);
inline const Value &operator[](int32 index) const;
// debugging
int32 GetCapacity() const { return fCapacity; }
private:
inline static void _MoveItems(Value *values, int32 offset, int32 count);
bool _Resize(size_t count);
inline int32 _IteratorIndex(const Iterator &iterator) const;
inline int32 _IteratorIndex(const ConstIterator &iterator) const;
private:
size_t fCapacity;
size_t fChunkSize;
int32 fItemCount;
Value *fItems;
};
// VectorIterator
template<typename Value>
class VectorIterator {
private:
typedef VectorIterator<Value> Iterator;
public:
inline VectorIterator<Value>()
: fElement(NULL)
{
}
inline VectorIterator<Value>(const Iterator &other)
: fElement(other.fElement)
{
}
inline Iterator &operator++()
{
if (fElement)
++fElement;
return *this;
}
inline Iterator operator++(int)
{
Iterator it(*this);
++*this;
return it;
}
inline Iterator &operator--()
{
if (fElement)
--fElement;
return *this;
}
inline Iterator operator--(int)
{
Iterator it(*this);
--*this;
return it;
}
inline Iterator &operator=(const Iterator &other)
{
fElement = other.fElement;
return *this;
}
inline bool operator==(const Iterator &other) const
{
return (fElement == other.fElement);
}
inline bool operator!=(const Iterator &other) const
{
return !(*this == other);
}
inline Value &operator*() const
{
return *fElement;
}
inline Value *operator->() const
{
return fElement;
}
inline operator bool() const
{
return fElement;
}
// private
public:
inline VectorIterator<Value>(Value *element)
: fElement(element)
{
}
inline Value *Element() const
{
return fElement;
}
protected:
Value *fElement;
};
// Vector
// constructor
/*! \brief Creates an empty vector.
\param chunkSize The granularity for the vector's capacity, i.e. the
minimal number of elements the capacity grows or shrinks when
necessary.
*/
_VECTOR_TEMPLATE_LIST
_VECTOR_CLASS_NAME::Vector(size_t chunkSize)
: fCapacity(0),
fChunkSize(chunkSize),
fItemCount(0),
fItems(NULL)
{
if (fChunkSize == 0 || fChunkSize > kMaximalChunkSize)
fChunkSize = kDefaultChunkSize;
_Resize(0);
}
// destructor
/*! \brief Frees all resources associated with the object.
The contained elements are destroyed. Note, that, if the element
type is a pointer type, only the pointer is destroyed, not the object
it points to.
*/
_VECTOR_TEMPLATE_LIST
_VECTOR_CLASS_NAME::~Vector()
{
MakeEmpty();
free(fItems);
}
// PushFront
/*! \brief Inserts a copy of the supplied value at the beginning of the
vector.
\param value The element to be inserted.
\return
- \c B_OK: Everything went fine.
- \c B_NO_MEMORY: Insufficient memory for this operation.
*/
_VECTOR_TEMPLATE_LIST
status_t
_VECTOR_CLASS_NAME::PushFront(const Value &value)
{
return Insert(value, 0);
}
// PushBack
/*! \brief Inserts a copy of the supplied value at the end of the vector.
\param value The element to be inserted.
\return
- \c B_OK: Everything went fine.
- \c B_NO_MEMORY: Insufficient memory for this operation.
*/
_VECTOR_TEMPLATE_LIST
status_t
_VECTOR_CLASS_NAME::PushBack(const Value &value)
{
return Insert(value, fItemCount);
}
// PopFront
/*! \brief Removes the first element of the vector.
Invocation on an empty vector is harmless.
*/
_VECTOR_TEMPLATE_LIST
void
_VECTOR_CLASS_NAME::PopFront()
{
if (fItemCount > 0)
Erase(0);
}
// PopBack
/*! \brief Removes the last element of the vector.
Invocation on an empty vector is harmless.
*/
_VECTOR_TEMPLATE_LIST
void
_VECTOR_CLASS_NAME::PopBack()
{
if (fItemCount > 0)
Erase(fItemCount - 1);
}
// _MoveItems
/*! \brief Moves elements within an array.
\param items The elements to be moved.
\param offset The index to which the elements shall be moved. May be
negative.
\param count The number of elements to be moved.
*/
_VECTOR_TEMPLATE_LIST
inline
void
_VECTOR_CLASS_NAME::_MoveItems(Value* items, int32 offset, int32 count)
{
if (count > 0 && offset != 0)
memmove(items + offset, items, count * sizeof(Value));
}
// Insert
/*! \brief Inserts a copy of the the supplied value at the given index.
\param value The value to be inserted.
\param index The index at which to insert the new element. It must
hold: 0 <= \a index <= Count().
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \a index is out of range.
- \c B_NO_MEMORY: Insufficient memory for this operation.
*/
_VECTOR_TEMPLATE_LIST
status_t
_VECTOR_CLASS_NAME::Insert(const Value &value, int32 index)
{
if (index < 0 || index > fItemCount)
return B_BAD_VALUE;
if (!_Resize(fItemCount + 1))
return B_NO_MEMORY;
_MoveItems(fItems + index, 1, fItemCount - index - 1);
new(fItems + index) Value(value);
return B_OK;
}
// Insert
/*! \brief Inserts a copy of the the supplied value at the given position.
\param value The value to be inserted.
\param iterator An iterator specifying the position at which to insert
the new element.
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \a iterator is is invalid.
- \c B_NO_MEMORY: Insufficient memory for this operation.
*/
_VECTOR_TEMPLATE_LIST
status_t
_VECTOR_CLASS_NAME::Insert(const Value &value, const Iterator &iterator)
{
int32 index = _IteratorIndex(iterator);
if (index >= 0)
return Insert(value, index);
return B_BAD_VALUE;
}
// Remove
/*! \brief Removes all elements of the supplied value.
\param value The value of the elements to be removed.
\return The number of removed occurrences.
*/
_VECTOR_TEMPLATE_LIST
int32
_VECTOR_CLASS_NAME::Remove(const Value &value)
{
int32 count = 0;
for (int32 i = fItemCount - 1; i >= 0; i--) {
if (ElementAt(i) == value) {
Erase(i);
count++;
}
}
return count;
}
// Erase
/*! \brief Removes the element at the given index.
\param index The position of the element to be removed.
\return An iterator referring to the element now being located at index
\a index (End(), if it was the last element that has been
removed), or Null(), if \a index was out of range.
*/
_VECTOR_TEMPLATE_LIST
_VECTOR_CLASS_NAME::Iterator
_VECTOR_CLASS_NAME::Erase(int32 index)
{
if (index >= 0 && index < fItemCount) {
fItems[index].~Value();
_MoveItems(fItems + index + 1, -1, fItemCount - index - 1);
_Resize(fItemCount - 1);
return Iterator(fItems + index);
}
return Null();
}
// Erase
/*! \brief Removes the element at the given position.
\param iterator An iterator referring to the element to be removed.
\return An iterator referring to the element succeeding the removed
one (End(), if it was the last element that has been
removed), or Null(), if \a iterator was an invalid iterator
(in this case including End()).
*/
_VECTOR_TEMPLATE_LIST
_VECTOR_CLASS_NAME::Iterator
_VECTOR_CLASS_NAME::Erase(const Iterator &iterator)
{
int32 index = _IteratorIndex(iterator);
if (index >= 0 && index < fItemCount)
return Erase(index);
return Null();
}
// Count
/*! \brief Returns the number of elements the vector contains.
\return The number of elements the vector contains.
*/
_VECTOR_TEMPLATE_LIST
inline
int32
_VECTOR_CLASS_NAME::Count() const
{
return fItemCount;
}
// IsEmpty
/*! \brief Returns whether the vector is empty.
\return \c true, if the vector is empty, \c false otherwise.
*/
_VECTOR_TEMPLATE_LIST
inline
bool
_VECTOR_CLASS_NAME::IsEmpty() const
{
return (fItemCount == 0);
}
// MakeEmpty
/*! \brief Removes all elements from the vector.
*/
_VECTOR_TEMPLATE_LIST
void
_VECTOR_CLASS_NAME::MakeEmpty()
{
for (int32 i = 0; i < fItemCount; i++)
fItems[i].~Value();
_Resize(0);
}
// Begin
/*! \brief Returns an iterator referring to the beginning of the vector.
If the vector is not empty, Begin() refers to its first element,
otherwise it is equal to End() and must not be dereferenced!
\return An iterator referring to the beginning of the vector.
*/
_VECTOR_TEMPLATE_LIST
inline
_VECTOR_CLASS_NAME::Iterator
_VECTOR_CLASS_NAME::Begin()
{
return Iterator(fItems);
}
// Begin
/*! \brief Returns an iterator referring to the beginning of the vector.
If the vector is not empty, Begin() refers to its first element,
otherwise it is equal to End() and must not be dereferenced!
\return An iterator referring to the beginning of the vector.
*/
_VECTOR_TEMPLATE_LIST
inline
_VECTOR_CLASS_NAME::ConstIterator
_VECTOR_CLASS_NAME::Begin() const
{
return ConstIterator(fItems);
}
// End
/*! \brief Returns an iterator referring to the end of the vector.
The position identified by End() is the one succeeding the last
element, i.e. it must not be dereferenced!
\return An iterator referring to the end of the vector.
*/
_VECTOR_TEMPLATE_LIST
inline
_VECTOR_CLASS_NAME::Iterator
_VECTOR_CLASS_NAME::End()
{
return Iterator(fItems + fItemCount);
}
// End
/*! \brief Returns an iterator referring to the end of the vector.
The position identified by End() is the one succeeding the last
element, i.e. it must not be dereferenced!
\return An iterator referring to the end of the vector.
*/
_VECTOR_TEMPLATE_LIST
inline
_VECTOR_CLASS_NAME::ConstIterator
_VECTOR_CLASS_NAME::End() const
{
return ConstIterator(fItems + fItemCount);
}
// Null
/*! \brief Returns an invalid iterator.
Null() is used as a return value, if something went wrong. It must
neither be incremented or decremented nor dereferenced!
\return An invalid iterator.
*/
_VECTOR_TEMPLATE_LIST
inline
_VECTOR_CLASS_NAME::Iterator
_VECTOR_CLASS_NAME::Null()
{
return Iterator(NULL);
}
// Null
/*! \brief Returns an invalid iterator.
Null() is used as a return value, if something went wrong. It must
neither be incremented or decremented nor dereferenced!
\return An invalid iterator.
*/
_VECTOR_TEMPLATE_LIST
inline
_VECTOR_CLASS_NAME::ConstIterator
_VECTOR_CLASS_NAME::Null() const
{
return ConstIterator(NULL);
}
// IteratorForIndex
/*! \brief Returns an iterator for a given index.
\return An iterator referring to the same element as \a index, or
End(), if \a index is out of range.
*/
_VECTOR_TEMPLATE_LIST
inline
_VECTOR_CLASS_NAME::Iterator
_VECTOR_CLASS_NAME::IteratorForIndex(int32 index)
{
if (index >= 0 && index <= fItemCount)
return Iterator(fItems + index);
return End();
}
// IteratorForIndex
/*! \brief Returns an iterator for a given index.
\return An iterator referring to the same element as \a index, or
End(), if \a index is out of range.
*/
_VECTOR_TEMPLATE_LIST
inline
_VECTOR_CLASS_NAME::ConstIterator
_VECTOR_CLASS_NAME::IteratorForIndex(int32 index) const
{
if (index >= 0 && index <= fItemCount)
return ConstIterator(fItems + index);
return End();
}
// ElementAt
/*! \brief Returns the element at a given index.
\param index The index identifying the element to be returned.
\return The element identified by the given index.
*/
_VECTOR_TEMPLATE_LIST
inline
const Value &
_VECTOR_CLASS_NAME::ElementAt(int32 index) const
{
if (index >= 0 && index < fItemCount)
return fItems[index];
// Return the 0th element by default. Unless the allocation failed, there
// is always a 0th element -- uninitialized perhaps.
return fItems[0];
}
// ElementAt
/*! \brief Returns the element at a given index.
\param index The index identifying the element to be returned.
\return The element identified by the given index.
*/
_VECTOR_TEMPLATE_LIST
inline
Value &
_VECTOR_CLASS_NAME::ElementAt(int32 index)
{
if (index >= 0 && index < fItemCount)
return fItems[index];
// Return the 0th element by default. Unless the allocation failed, there
// is always a 0th element -- uninitialized perhaps.
return fItems[0];
}
// IndexOf
/*! \brief Returns the index of the next element with the specified value.
\param value The value of the element to be found.
\param start The index at which to be started to search for the element.
\return The index of the found element, or \c -1, if no further element
with the given value could be found or \a index is out of range.
*/
_VECTOR_TEMPLATE_LIST
int32
_VECTOR_CLASS_NAME::IndexOf(const Value &value, int32 start) const
{
if (start >= 0) {
for (int32 i = start; i < fItemCount; i++) {
if (fItems[i] == value)
return i;
}
}
return -1;
}
// Find
/*! \brief Returns an iterator referring to the next element with the
specified value.
\param value The value of the element to be found.
\return An iterator referring to the found element, or End(), if no
further with the given value could be found.
*/
_VECTOR_TEMPLATE_LIST
inline
_VECTOR_CLASS_NAME::Iterator
_VECTOR_CLASS_NAME::Find(const Value &value)
{
return Find(value, Begin());
}
// Find
/*! \brief Returns an iterator referring to the next element with the
specified value.
\param value The value of the element to be found.
\param start And iterator specifying where to start searching for the
element.
\return An iterator referring to the found element, or End(), if no
further with the given value could be found or \a start was
invalid.
*/
_VECTOR_TEMPLATE_LIST
_VECTOR_CLASS_NAME::Iterator
_VECTOR_CLASS_NAME::Find(const Value &value, const Iterator &start)
{
int32 index = IndexOf(value, _IteratorIndex(start));
if (index >= 0)
return Iterator(fItems + index);
return End();
}
// Find
/*! \brief Returns an iterator referring to the of the next element with the
specified value.
\param value The value of the element to be found.
\return An iterator referring to the found element, or End(), if no
further with the given value could be found.
*/
_VECTOR_TEMPLATE_LIST
inline
_VECTOR_CLASS_NAME::ConstIterator
_VECTOR_CLASS_NAME::Find(const Value &value) const
{
return Find(value, Begin());
}
// Find
/*! \brief Returns an iterator referring to the of the next element with the
specified value.
\param value The value of the element to be found.
\param start And iterator specifying where to start searching for the
element.
\return An iterator referring to the found element, or End(), if no
further with the given value could be found or \a start was
invalid.
*/
_VECTOR_TEMPLATE_LIST
_VECTOR_CLASS_NAME::ConstIterator
_VECTOR_CLASS_NAME::Find(const Value &value, const ConstIterator &start) const
{
int32 index = IndexOf(value, _IteratorIndex(start));
if (index >= 0)
return ConstIterator(fItems + index);
return End();
}
// []
/*! \brief Semantically equivalent to ElementAt().
*/
_VECTOR_TEMPLATE_LIST
inline
Value &
_VECTOR_CLASS_NAME::operator[](int32 index)
{
return ElementAt(index);
}
// []
/*! \brief Semantically equivalent to ElementAt().
*/
_VECTOR_TEMPLATE_LIST
inline
const Value &
_VECTOR_CLASS_NAME::operator[](int32 index) const
{
return ElementAt(index);
}
// _Resize
/*! \brief Resizes the vector.
The internal element array will be grown or shrunk to the next multiple
of \a fChunkSize >= \a count, but no less than \a fChunkSize.
Also adjusts \a fItemCount according to the supplied \a count, but does
not invoke a destructor or constructor on any element.
\param count The number of element.
\return \c true, if everything went fine, \c false, if the memory
allocation failed.
*/
_VECTOR_TEMPLATE_LIST
bool
_VECTOR_CLASS_NAME::_Resize(size_t count)
{
bool result = true;
// calculate the new capacity
int32 newSize = count;
if (newSize <= 0)
newSize = 1;
newSize = ((newSize - 1) / fChunkSize + 1) * fChunkSize;
// resize if necessary
if ((size_t)newSize != fCapacity) {
Value* newItems = (Value*)realloc(fItems, newSize * sizeof(Value));
if (newItems) {
fItems = newItems;
fCapacity = newSize;
} else
result = false;
}
if (result)
fItemCount = count;
return result;
}
// _IteratorIndex
/*! \brief Returns index of the element the supplied iterator refers to.
\return The index of the element the supplied iterator refers to, or
\c -1, if the iterator is invalid (End() is considered valid
here, and Count() is returned).
*/
_VECTOR_TEMPLATE_LIST
inline
int32
_VECTOR_CLASS_NAME::_IteratorIndex(const Iterator &iterator) const
{
if (iterator.Element()) {
int32 index = iterator.Element() - fItems;
if (index >= 0 && index <= fItemCount)
return index;
}
return -1;
}
// _IteratorIndex
/*! \brief Returns index of the element the supplied iterator refers to.
\return The index of the element the supplied iterator refers to, or
\c -1, if the iterator is invalid (End() is considered valid
here, and Count() is returned).
*/
_VECTOR_TEMPLATE_LIST
inline
int32
_VECTOR_CLASS_NAME::_IteratorIndex(const ConstIterator &iterator) const
{
if (iterator.Element()) {
int32 index = iterator.Element() - fItems;
if (index >= 0 && index <= fItemCount)
return index;
}
return -1;
}
#endif // _VECTOR_H
@@ -0,0 +1,359 @@
// FileSystem.cpp
#include "AutoLocker.h"
#include "Compatibility.h"
#include "Debug.h"
#include "FileSystem.h"
#include "HashMap.h"
#include "KernelRequestHandler.h"
#include "PortReleaser.h"
#include "RequestAllocator.h"
#include "RequestPort.h"
#include "Requests.h"
#include "Settings.h"
#include "SingleReplyRequestHandler.h"
#include "Volume.h"
// The time after which the notification thread times out at the port and
// restarts the loop. Of interest only when the FS is deleted. It is the
// maximal time the destructor has to wait for the thread.
static const bigtime_t kNotificationRequestTimeout = 50000; // 50 ms
// SelectSyncMap
struct FileSystem::SelectSyncMap
: public SynchronizedHashMap<HashKey32<selectsync*>, int32*> {
};
// constructor
FileSystem::FileSystem(const char* name, RequestPort* initPort, status_t* error)
: LazyInitializable(),
Referencable(),
fVolumes(),
fVolumeLock(),
fName(name),
fInitPort(initPort),
fNotificationPort(NULL),
fNotificationThread(-1),
fPortPool(),
fSelectSyncs(NULL),
fSettings(NULL),
fUserlandServerTeam(-1),
fTerminating(false)
{
if (error)
*error = (fName.GetLength() == 0 ? B_NO_MEMORY : B_OK);
}
// destructor
FileSystem::~FileSystem()
{
fTerminating = true;
// wait for the notification thread to terminate
if (fNotificationThread >= 0) {
int32 result;
wait_for_thread(fNotificationThread, &result);
}
// delete our data structures
if (fSelectSyncs) {
for (SelectSyncMap::Iterator it = fSelectSyncs->GetIterator();
it.HasNext();) {
SelectSyncMap::Entry entry = it.Next();
delete entry.value;
}
delete fSelectSyncs;
}
delete fSettings;
}
// GetName
const char*
FileSystem::GetName() const
{
return fName.GetString();
}
// GetPortPool
RequestPortPool*
FileSystem::GetPortPool()
{
return &fPortPool;
}
// Mount
status_t
FileSystem::Mount(nspace_id id, const char* device, ulong flags,
const char* parameters, int32 len, Volume** _volume)
{
// check initialization and parameters
if (InitCheck() != B_OK)
return InitCheck();
if (!_volume)
return B_BAD_VALUE;
// create volume
Volume* volume = new(nothrow) Volume(this, id);
if (!volume)
return B_NO_MEMORY;
// add volume to the volume list
fVolumeLock.Lock();
status_t error = fVolumes.PushBack(volume);
fVolumeLock.Unlock();
if (error != B_OK)
return error;
// mount volume
error = volume->Mount(device, flags, parameters, len);
if (error != B_OK) {
fVolumeLock.Lock();
fVolumes.Remove(volume);
fVolumeLock.Unlock();
volume->RemoveReference();
return error;
}
*_volume = volume;
return error;
}
// Initialize
status_t
FileSystem::Initialize(const char* deviceName, const char* parameters,
size_t len)
{
// get a free port
RequestPort* port = fPortPool.AcquirePort();
if (!port)
return B_ERROR;
PortReleaser _(&fPortPool, port);
// prepare the request
RequestAllocator allocator(port->GetPort());
MountVolumeRequest* request;
status_t error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
error = allocator.AllocateString(request->device, deviceName);
if (error == B_OK)
error = allocator.AllocateData(request->parameters, parameters, len, 1);
if (error != B_OK)
return error;
// send the request
SingleReplyRequestHandler handler(MOUNT_VOLUME_REPLY);
InitializeVolumeReply* reply;
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
return error;
}
// VolumeUnmounted
void
FileSystem::VolumeUnmounted(Volume* volume)
{
fVolumeLock.Lock();
fVolumes.Remove(volume);
fVolumeLock.Unlock();
}
// GetVolume
Volume*
FileSystem::GetVolume(nspace_id id)
{
AutoLocker<Locker> _(fVolumeLock);
for (Vector<Volume*>::Iterator it = fVolumes.Begin();
it != fVolumes.End();
it++) {
Volume* volume = *it;
if (volume->GetID() == id) {
volume->AddReference();
return volume;
}
}
return NULL;
}
// GetIOCtlInfo
const IOCtlInfo*
FileSystem::GetIOCtlInfo(int command) const
{
return (fSettings ? fSettings->GetIOCtlInfo(command) : NULL);
}
// AddSelectSyncEntry
status_t
FileSystem::AddSelectSyncEntry(selectsync* sync)
{
AutoLocker<SelectSyncMap> _(fSelectSyncs);
int32* count = fSelectSyncs->Get(sync);
if (!count) {
count = new(nothrow) int32(0);
if (!count)
return B_NO_MEMORY;
status_t error = fSelectSyncs->Put(sync, count);
if (error != B_OK) {
delete count;
return error;
}
}
(*count)++;
return B_OK;
}
// RemoveSelectSyncEntry
void
FileSystem::RemoveSelectSyncEntry(selectsync* sync)
{
AutoLocker<SelectSyncMap> _(fSelectSyncs);
if (int32* count = fSelectSyncs->Get(sync)) {
if (--(*count) <= 0) {
fSelectSyncs->Remove(sync);
delete count;
}
}
}
// KnowsSelectSyncEntry
bool
FileSystem::KnowsSelectSyncEntry(selectsync* sync)
{
return fSelectSyncs->ContainsKey(sync);
}
// IsUserlandServerThread
bool
FileSystem::IsUserlandServerThread() const
{
thread_info info;
get_thread_info(find_thread(NULL), &info);
return (info.team == fUserlandServerTeam);
}
// FirstTimeInit
status_t
FileSystem::FirstTimeInit()
{
if (fName.GetLength() == 0)
RETURN_ERROR(B_NO_MEMORY);
PRINT(("FileSystem::FirstTimeInit(): %s\n", fName.GetString()));
// create the select sync entry map
fSelectSyncs = new(nothrow) SelectSyncMap;
if (!fSelectSyncs)
return B_NO_MEMORY;
// prepare the request
RequestAllocator allocator(fInitPort->GetPort());
FSConnectRequest* request;
status_t error = AllocateRequest(allocator, &request);
if (error != B_OK)
RETURN_ERROR(error);
error = allocator.AllocateString(request->fsName, fName.GetString());
if (error != B_OK)
RETURN_ERROR(error);
// send the request
SingleReplyRequestHandler handler(FS_CONNECT_REPLY);
FSConnectReply* reply;
error = fInitPort->SendRequest(&allocator, &handler, (Request**)&reply);
if (error != B_OK)
RETURN_ERROR(error);
RequestReleaser requestReleaser(fInitPort, reply);
// process the reply
if (reply->error != B_OK)
RETURN_ERROR(reply->error);
// get the port infos
int32 count = reply->portInfoCount;
if (count < 2)
RETURN_ERROR(B_BAD_DATA);
if (reply->portInfos.GetSize() != count * (int32)sizeof(Port::Info))
RETURN_ERROR(B_BAD_DATA);
Port::Info* infos = (Port::Info*)reply->portInfos.GetData();
// create the request ports
// the notification port
fNotificationPort = new(nothrow) RequestPort(infos);
if (!fNotificationPort)
RETURN_ERROR(B_NO_MEMORY);
error = fNotificationPort->InitCheck();
if (error != B_OK)
return error;
// the other request ports
for (int32 i = 1; i < count; i++) {
RequestPort* port = new(nothrow) RequestPort(infos + i);
if (!port)
RETURN_ERROR(B_NO_MEMORY);
error = port->InitCheck();
if (error == B_OK)
error = fPortPool.AddPort(port);
if (error != B_OK) {
delete port;
RETURN_ERROR(error);
}
}
// get the userland team
port_info portInfo;
error = get_port_info(infos[0].owner_port, &portInfo);
if (error != B_OK)
RETURN_ERROR(error);
fUserlandServerTeam = portInfo.team;
// print some info about the userland team
D(
PRINT((" userland team is: %ld\n", fUserlandServerTeam));
int32 cookie = 0;
thread_info threadInfo;
while (get_next_thread_info(fUserlandServerTeam, &cookie, &threadInfo)
== B_OK) {
PRINT((" userland thread: %ld: `%s'\n", threadInfo.thread,
threadInfo.name));
}
);
// load the settings
fSettings = new(nothrow) Settings;
if (fSettings) {
status_t settingsError = fSettings->SetTo(fName.GetString());
if (settingsError != B_OK) {
PRINT(("Failed to load settings: %s\n", strerror(settingsError)));
delete fSettings;
fSettings = NULL;
} else
fSettings->Dump();
} else
ERROR(("Failed to allocate settings.\n"));
// spawn the notification thread
#if USER
fNotificationThread = spawn_thread(_NotificationThreadEntry,
"UFS notification thread", B_NORMAL_PRIORITY, this);
#else
fNotificationThread = spawn_kernel_thread(_NotificationThreadEntry,
"UFS notification thread", B_NORMAL_PRIORITY, this);
#endif
if (fNotificationThread < 0)
RETURN_ERROR(fNotificationThread);
resume_thread(fNotificationThread);
RETURN_ERROR(error);
}
// _NotificationThreadEntry
int32
FileSystem::_NotificationThreadEntry(void* data)
{
return ((FileSystem*)data)->_NotificationThread();
}
// _NotificationThread
int32
FileSystem::_NotificationThread()
{
// process the notification requests until the FS is deleted
while (!fTerminating) {
if (fNotificationPort->InitCheck() != B_OK)
return fNotificationPort->InitCheck();
KernelRequestHandler handler(this, NO_REQUEST);
fNotificationPort->HandleRequests(&handler, NULL,
kNotificationRequestTimeout);
}
// We eat all remaining notification requests, so that they aren't
// presented to the file system, when it is mounted next time.
// TODO: We should probably use a special handler that sends an ack reply,
// but ignores the requests otherwise.
KernelRequestHandler handler(this, NO_REQUEST);
fNotificationPort->HandleRequests(&handler, NULL, 0);
return 0;
}
@@ -0,0 +1,80 @@
// FileSystem.h
#ifndef USERLAND_FS_FILE_SYSTEM_H
#define USERLAND_FS_FILE_SYSTEM_H
#include <fsproto.h>
#include "LazyInitializable.h"
#include "Locker.h"
#include "Referencable.h"
#include "RequestPortPool.h"
#include "String.h"
#include "Vector.h"
namespace UserlandFSUtil {
class RequestPort;
}
using UserlandFSUtil::RequestPort;
struct IOCtlInfo;
class Settings;
class Volume;
class FileSystem : public LazyInitializable, public Referencable {
public:
FileSystem(const char* name,
RequestPort* initPort,
status_t* error);
~FileSystem();
const char* GetName() const;
RequestPortPool* GetPortPool();
status_t Mount(nspace_id id, const char* device,
ulong flags, const char* parameters,
int32 len, Volume** volume);
status_t Initialize(const char* deviceName,
const char* parameters, size_t len);
void VolumeUnmounted(Volume* volume);
Volume* GetVolume(nspace_id id);
const IOCtlInfo* GetIOCtlInfo(int command) const;
status_t AddSelectSyncEntry(selectsync* sync);
void RemoveSelectSyncEntry(selectsync* sync);
bool KnowsSelectSyncEntry(selectsync* sync);
bool IsUserlandServerThread() const;
protected:
virtual status_t FirstTimeInit();
private:
static int32 _NotificationThreadEntry(void* data);
int32 _NotificationThread();
private:
friend class KernelDebug;
struct SelectSyncEntry;
struct SelectSyncMap;
Vector<Volume*> fVolumes;
Locker fVolumeLock;
String fName;
RequestPort* fInitPort;
RequestPort* fNotificationPort;
thread_id fNotificationThread;
RequestPortPool fPortPool;
SelectSyncMap* fSelectSyncs;
Settings* fSettings;
team_id fUserlandServerTeam;
volatile bool fTerminating;
};
#endif // USERLAND_FS_FILE_SYSTEM_H
@@ -0,0 +1,16 @@
// IOCtlInfo.h
#ifndef USERLAND_FS_IOCTL_INFO_H
#define USERLAND_FS_IOCTL_INFO_H
#include <SupportDefs.h>
// IOCtlInfo
struct IOCtlInfo {
int command;
bool isBuffer;
int32 bufferSize;
int32 writeBufferSize;
};
#endif // USERLAND_FS_IOCTL_INFO_H
@@ -0,0 +1,57 @@
SubDir HAIKU_TOP src tests add-ons kernel file_systems userlandfs r5 src
kernel_add_on ;
SetSubDirSupportedPlatforms r5 bone dano ;
local userlandFSTop = [ FDirName $(HAIKU_TOP) src tests add-ons kernel
file_systems userlandfs r5 ] ;
local userlandFSIncludes = [ FDirName $(userlandFSTop) headers ] ;
SubDirSysHdrs [ FDirName $(userlandFSIncludes) public ] ;
SubDirHdrs [ FDirName $(userlandFSIncludes) private ] ;
SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ;
SEARCH_SOURCE += [ FDirName $(userlandFSTop) src private ] ;
SEARCH_SOURCE += [ FDirName $(userlandFSTop) src shared ] ;
DEFINES += DEBUG_APP="\\\"userlandfs\\\"" ;
local kernelC++ ;
if $(OSPLAT) = X86 {
kernelC++ += kernel-cpp.cpp ;
SubDirC++Flags -include [ FDirName $(SUBDIR) kernel-cpp.h ] ;
}
KernelAddon <test>userlandfs
: AreaSupport.cpp
Debug.cpp
DispatcherDefs.cpp
LazyInitializable.cpp
Locker.cpp
ObjectTracker.cpp
Port.cpp
Referencable.cpp
Request.cpp
RequestAllocator.cpp
RequestHandler.cpp
RequestPort.cpp
RequestPortPool.cpp
Requests.cpp
SingleReplyRequestHandler.cpp
String.cpp
userlandfs_ioctl.cpp
FileSystem.cpp
kernel_interface.cpp
KernelDebug.cpp
KernelRequestHandler.cpp
Settings.cpp
UserlandFS.cpp
Volume.cpp
$(kernelC++)
: $(HAIKU_GCC_LIBGCC)
# TARGET_GCC_LIBGCC is not defined for TARGET_PLATFORM != haiku,
# but the compiler is the same in this case anyway.
;
@@ -0,0 +1,109 @@
// KernelDebug.cpp
#include <KernelExport.h>
#include "Debug.h"
#include "FileSystem.h"
#include "KernelDebug.h"
#include "RequestPort.h"
#include "RequestPortPool.h"
#include "UserlandFS.h"
#include "Volume.h"
static vint32 sCommandsAdded = 0;
// DebugUFS
int
KernelDebug::DebugUFS(int argc, char** argv)
{
typedef HashMap<String, FileSystem*> KDebugFSMap;
UserlandFS* userlandFS = UserlandFS::GetUserlandFS();
KDebugFSMap& fileSystems = userlandFS->fFileSystems->GetUnsynchronizedMap();
for (KDebugFSMap::Iterator it = fileSystems.GetIterator();
it.HasNext();) {
KDebugFSMap::Entry entry = it.Next();
FileSystem* fs = entry.value;
kprintf("file system %p: %s\n", fs, fs->GetName());
kprintf(" port pool %p\n", fs->GetPortPool());
int32 volumeCount = fs->fVolumes.Count();
for (int32 i = 0; i < volumeCount; i++) {
Volume* volume = fs->fVolumes.ElementAt(i);
kprintf(" volume %p: %ld\n", volume, volume->GetID());
}
}
return 0;
}
// DebugPortPool
int
KernelDebug::DebugPortPool(int argc, char** argv)
{
if (argc < 2) {
kprintf("usage: ufs_portpool <port pool pointer>\n");
return 0;
}
RequestPortPool *portPool = (RequestPortPool*)parse_expression(argv[1]);
kprintf("free ports:\n");
for (int32 i = 0; i < portPool->fFreePorts; i++) {
kprintf(" port %p\n", portPool->fPorts[i].port);
}
kprintf("used ports:\n");
for (int32 i = portPool->fFreePorts; i < portPool->fPortCount; i++) {
kprintf(" port %p, owner: %ld, count: %ld\n", portPool->fPorts[i].port,
portPool->fPorts[i].owner, portPool->fPorts[i].count);
}
return 0;
}
// DebugPort
int
KernelDebug::DebugPort(int argc, char** argv)
{
if (argc < 2) {
kprintf("usage: ufs_port <port pointer>\n");
return 0;
}
RequestPort *port = (RequestPort*)parse_expression(argv[1]);
kprintf("port %p:\n", port);
kprintf(" status : %lx\n", port->fPort.fInitStatus);
kprintf(" is owner : %d\n", port->fPort.fOwner);
kprintf(" owner port: %ld\n", port->fPort.fInfo.owner_port);
kprintf(" client port: %ld\n", port->fPort.fInfo.client_port);
kprintf(" size: %ld\n", port->fPort.fInfo.size);
kprintf(" capacity: %ld\n", port->fPort.fCapacity);
kprintf(" message size: %ld\n", port->fPort.fMessageSize);
kprintf(" buffer: %p\n", port->fPort.fBuffer);
return 0;
}
// #pragma mark -
// AddDebuggerCommands
void
KernelDebug::AddDebuggerCommands()
{
if (atomic_add(&sCommandsAdded, 1) > 0)
return;
PRINT(("KernelDebug::AddDebuggerCommands(): adding debugger commands\n"));
add_debugger_command("ufs", DebugUFS, "prints general info about "
"userland FS");
add_debugger_command("ufs_portpool", DebugPortPool,
"ufs_portpool <port pool pointer> - prints info about a "
"userland FS port pool");
add_debugger_command("ufs_port", DebugPort,
"ufs_port <port pointer> - prints info about a userland FS port");
}
// RemoveDebuggerCommands
void
KernelDebug::RemoveDebuggerCommands()
{
if (atomic_add(&sCommandsAdded, -1) > 1)
return;
PRINT(("KernelDebug::RemoveDebuggerCommands(): removing debugger "
"commands\n"));
remove_debugger_command("ufs_port", DebugPort);
remove_debugger_command("ufs_portpool", DebugPortPool);
remove_debugger_command("ufs", DebugUFS);
}
@@ -0,0 +1,23 @@
// KernelDebug.h
#ifndef USERLAND_FS_KERNEL_DEBUG_H
#define USERLAND_FS_KERNEL_DEBUG_H
class KernelDebug {
public:
static void AddDebuggerCommands();
static void RemoveDebuggerCommands();
private:
static int DebugUFS(int argc, char** argv);
static int DebugPortPool(int argc, char** argv);
static int DebugPort(int argc, char** argv);
};
// no kernel debugger commands in userland
#if USER
inline void KernelDebug::AddDebuggerCommands() {}
inline void KernelDebug::RemoveDebuggerCommands() {}
#endif
#endif // USERLAND_FS_KERNEL_DEBUG_H
@@ -0,0 +1,355 @@
// KernelRequestHandler.cpp
#include "Compatibility.h"
#include "Debug.h"
#include "FileSystem.h"
#include "KernelRequestHandler.h"
#include "RequestPort.h"
#include "Requests.h"
#include "Volume.h"
// VolumePutter
class VolumePutter {
public:
VolumePutter(Volume* volume) : fVolume(volume) {}
~VolumePutter()
{
if (fVolume)
fVolume->RemoveReference();
}
private:
Volume *fVolume;
};
// constructor
KernelRequestHandler::KernelRequestHandler(Volume* volume, uint32 expectedReply)
: RequestHandler(),
fFileSystem(volume->GetFileSystem()),
fVolume(volume),
fExpectedReply(expectedReply)
{
}
// constructor
KernelRequestHandler::KernelRequestHandler(FileSystem* fileSystem,
uint32 expectedReply)
: RequestHandler(),
fFileSystem(fileSystem),
fVolume(NULL),
fExpectedReply(expectedReply)
{
}
// destructor
KernelRequestHandler::~KernelRequestHandler()
{
}
// HandleRequest
status_t
KernelRequestHandler::HandleRequest(Request* request)
{
if (request->GetType() == fExpectedReply) {
fDone = true;
return B_OK;
}
switch (request->GetType()) {
// notifications
case NOTIFY_LISTENER_REQUEST:
return _HandleRequest((NotifyListenerRequest*)request);
case NOTIFY_SELECT_EVENT_REQUEST:
return _HandleRequest((NotifySelectEventRequest*)request);
case SEND_NOTIFICATION_REQUEST:
return _HandleRequest((SendNotificationRequest*)request);
// vnodes
case GET_VNODE_REQUEST:
return _HandleRequest((GetVNodeRequest*)request);
case PUT_VNODE_REQUEST:
return _HandleRequest((PutVNodeRequest*)request);
case NEW_VNODE_REQUEST:
return _HandleRequest((NewVNodeRequest*)request);
case REMOVE_VNODE_REQUEST:
return _HandleRequest((RemoveVNodeRequest*)request);
case UNREMOVE_VNODE_REQUEST:
return _HandleRequest((UnremoveVNodeRequest*)request);
case IS_VNODE_REMOVED_REQUEST:
return _HandleRequest((IsVNodeRemovedRequest*)request);
}
PRINT(("KernelRequestHandler::HandleRequest(): unexpected request: %lu\n",
request->GetType()));
return B_BAD_DATA;
}
// #pragma mark -
// #pragma mark ----- notifications -----
// _HandleRequest
status_t
KernelRequestHandler::_HandleRequest(NotifyListenerRequest* request)
{
// check and executed the request
status_t result = B_OK;
if (fVolume && request->nsid != fVolume->GetID())
result = B_BAD_VALUE;
// check the name
char* name = (char*)request->name.GetData();
int32 nameLen = request->name.GetSize();
if (name && (nameLen <= 0 || strnlen(name, nameLen) < 1))
name = NULL;
else if (name)
name[nameLen - 1] = '\0';
if (!name) {
switch (request->operation) {
case B_ENTRY_CREATED:
case B_ENTRY_MOVED:
case B_ATTR_CHANGED:
ERROR(("notify_listener(): NULL name for opcode: %ld\n",
request->operation));
result = B_BAD_VALUE;
break;
case B_ENTRY_REMOVED:
case B_STAT_CHANGED:
break;
}
}
// execute the request
if (result == B_OK) {
PRINT(("notify_listener(%ld, %ld, %Ld, %Ld, %Ld, `%s')\n",
request->operation, request->nsid, request->vnida, request->vnidb,
request->vnidc, name));
result = notify_listener(request->operation, request->nsid,
request->vnida, request->vnidb, request->vnidc, name);
}
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
NotifyListenerReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
return error;
reply->error = result;
// send the reply
return fPort->SendRequest(&allocator);
}
// _HandleRequest
status_t
KernelRequestHandler::_HandleRequest(NotifySelectEventRequest* request)
{
// check and executed the request
status_t result = B_OK;
if (fFileSystem->KnowsSelectSyncEntry(request->sync)) {
PRINT(("notify_select_event(%p, %lu)\n", request->sync, request->ref));
notify_select_event(request->sync, request->ref);
} else
result = B_BAD_VALUE;
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
NotifySelectEventReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
return error;
reply->error = result;
// send the reply
return fPort->SendRequest(&allocator);
}
// _HandleRequest
status_t
KernelRequestHandler::_HandleRequest(SendNotificationRequest* request)
{
// check and executed the request
status_t result = B_OK;
if (fVolume && request->nsida != fVolume->GetID()
&& request->nsidb != fVolume->GetID()) {
result = B_BAD_VALUE;
}
// check the name
char* name = (char*)request->name.GetData();
int32 nameLen = request->name.GetSize();
if (name && (nameLen <= 0 || strnlen(name, nameLen) < 1))
name = NULL;
else if (name)
name[nameLen - 1] = '\0';
if (!name) {
switch (request->operation) {
case B_ENTRY_CREATED:
case B_ENTRY_MOVED:
ERROR(("send_notification(): NULL name for opcode: %ld\n",
request->operation));
result = B_BAD_VALUE;
break;
case B_ENTRY_REMOVED:
break;
}
}
// execute the request
if (result == B_OK) {
PRINT(("send_notification(%ld, %ld, %lu, %ld, %ld, %ld, %Ld, %Ld, %Ld, "
"`%s')\n", request->port, request->token, request->what,
request->operation, request->nsida, request->nsidb, request->vnida,
request->vnidb, request->vnidc, name));
result = send_notification(request->port, request->token, request->what,
request->operation, request->nsida, request->nsidb, request->vnida,
request->vnidb, request->vnidc, name);
}
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
SendNotificationReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
return error;
reply->error = result;
// send the reply
return fPort->SendRequest(&allocator);
}
// #pragma mark -
// #pragma mark ----- vnodes -----
// _HandleRequest
status_t
KernelRequestHandler::_HandleRequest(GetVNodeRequest* request)
{
// check and executed the request
Volume* volume = NULL;
status_t result = _GetVolume(request->nsid, &volume);
VolumePutter _(volume);
void* node;
if (result == B_OK)
result = volume->GetVNode(request->vnid, &node);
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
GetVNodeReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
return error;
reply->error = result;
reply->node = node;
// send the reply
return fPort->SendRequest(&allocator);
}
// _HandleRequest
status_t
KernelRequestHandler::_HandleRequest(PutVNodeRequest* request)
{
// check and executed the request
Volume* volume = NULL;
status_t result = _GetVolume(request->nsid, &volume);
VolumePutter _(volume);
if (result == B_OK)
result = volume->PutVNode(request->vnid);
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
PutVNodeReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
return error;
reply->error = result;
// send the reply
return fPort->SendRequest(&allocator);
}
// _HandleRequest
status_t
KernelRequestHandler::_HandleRequest(NewVNodeRequest* request)
{
// check and executed the request
Volume* volume = NULL;
status_t result = _GetVolume(request->nsid, &volume);
VolumePutter _(volume);
if (result == B_OK)
result = volume->NewVNode(request->vnid, request->node);
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
NewVNodeReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
return error;
reply->error = result;
// send the reply
return fPort->SendRequest(&allocator);
}
// _HandleRequest
status_t
KernelRequestHandler::_HandleRequest(RemoveVNodeRequest* request)
{
// check and executed the request
Volume* volume = NULL;
status_t result = _GetVolume(request->nsid, &volume);
VolumePutter _(volume);
if (result == B_OK)
result = volume->RemoveVNode(request->vnid);
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
RemoveVNodeReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
return error;
reply->error = result;
// send the reply
return fPort->SendRequest(&allocator);
}
// _HandleRequest
status_t
KernelRequestHandler::_HandleRequest(UnremoveVNodeRequest* request)
{
// check and executed the request
Volume* volume = NULL;
status_t result = _GetVolume(request->nsid, &volume);
VolumePutter _(volume);
if (result == B_OK)
result = volume->UnremoveVNode(request->vnid);
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
UnremoveVNodeReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
return error;
reply->error = result;
// send the reply
return fPort->SendRequest(&allocator);
}
// _HandleRequest
status_t
KernelRequestHandler::_HandleRequest(IsVNodeRemovedRequest* request)
{
// check and executed the request
Volume* volume = NULL;
status_t result = _GetVolume(request->nsid, &volume);
VolumePutter _(volume);
if (result == B_OK)
result = volume->IsVNodeRemoved(request->vnid);
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
IsVNodeRemovedReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
return error;
reply->error = (result < 0 ? result : B_OK);
reply->result = result;
// send the reply
return fPort->SendRequest(&allocator);
}
// _GetVolume
status_t
KernelRequestHandler::_GetVolume(nspace_id id, Volume** volume)
{
if (fVolume) {
if (fVolume->GetID() != id) {
*volume = NULL;
return B_BAD_VALUE;
}
fVolume->AddReference();
*volume = fVolume;
return B_OK;
}
*volume = fFileSystem->GetVolume(id);
return (*volume ? B_OK : B_BAD_VALUE);
}
@@ -0,0 +1,70 @@
// KernelRequestHandler.h
#ifndef USERLAND_FS_KERNEL_REQUEST_HANDLER_H
#define USERLAND_FS_KERNEL_REQUEST_HANDLER_H
#include <fsproto.h>
#include "RequestHandler.h"
namespace UserlandFSUtil {
class GetVNodeRequest;
class IsVNodeRemovedRequest;
class NewVNodeRequest;
class NotifyListenerRequest;
class NotifySelectEventRequest;
class PutVNodeRequest;
class RemoveVNodeRequest;
class SendNotificationRequest;
class UnremoveVNodeRequest;
}
using UserlandFSUtil::GetVNodeRequest;
using UserlandFSUtil::IsVNodeRemovedRequest;
using UserlandFSUtil::NewVNodeRequest;
using UserlandFSUtil::NotifyListenerRequest;
using UserlandFSUtil::NotifySelectEventRequest;
using UserlandFSUtil::PutVNodeRequest;
using UserlandFSUtil::RemoveVNodeRequest;
using UserlandFSUtil::SendNotificationRequest;
using UserlandFSUtil::UnremoveVNodeRequest;
using UserlandFSUtil::GetVNodeRequest;
class Volume;
class KernelRequestHandler : public RequestHandler {
public:
KernelRequestHandler(Volume* volume,
uint32 expectedReply);
KernelRequestHandler(FileSystem* fileSystem,
uint32 expectedReply);
virtual ~KernelRequestHandler();
virtual status_t HandleRequest(Request* request);
private:
// notifications
status_t _HandleRequest(NotifyListenerRequest* request);
status_t _HandleRequest(
NotifySelectEventRequest* request);
status_t _HandleRequest(
SendNotificationRequest* request);
// vnodes
status_t _HandleRequest(GetVNodeRequest* request);
status_t _HandleRequest(PutVNodeRequest* request);
status_t _HandleRequest(NewVNodeRequest* request);
status_t _HandleRequest(RemoveVNodeRequest* request);
status_t _HandleRequest(UnremoveVNodeRequest* request);
status_t _HandleRequest(IsVNodeRemovedRequest* request);
status_t _GetVolume(nspace_id id, Volume** volume);
private:
FileSystem* fFileSystem;
Volume* fVolume;
uint32 fExpectedReply;
};
#endif // USERLAND_FS_KERNEL_REQUEST_HANDLER_H
@@ -0,0 +1,29 @@
// PortReleaser.h
#ifndef USERLAND_FS_PORT_RELEASER_H
#define USERLAND_FS_PORT_RELEASER_H
#include "FileSystem.h"
#include "RequestPortPool.h"
// PortReleaser
class PortReleaser {
public:
PortReleaser(RequestPortPool* portPool, RequestPort* port)
: fPortPool(portPool),
fPort(port)
{
}
~PortReleaser()
{
if (fPort && fPortPool)
fPortPool->ReleasePort(fPort);
}
private:
RequestPortPool* fPortPool;
RequestPort* fPort;
};
#endif // USERLAND_FS_PORT_RELEASER_H
@@ -0,0 +1,130 @@
// RequestPortPool.cpp
#include "AutoLocker.h"
#include "Debug.h"
#include "RequestPort.h"
#include "RequestPortPool.h"
typedef AutoLocker<RequestPortPool> PoolLocker;
// constructor
RequestPortPool::RequestPortPool()
: fPorts(NULL),
fPortCount(0),
fFreePorts(0),
fFreePortSemaphore(-1),
fDisconnected(false)
{
fFreePortSemaphore = create_sem(0, "request port pool");
}
// destructor
RequestPortPool::~RequestPortPool()
{
delete_sem(fFreePortSemaphore);
free(fPorts);
}
// InitCheck
status_t
RequestPortPool::InitCheck() const
{
if (fFreePortSemaphore < 0)
return fFreePortSemaphore;
return B_OK;
}
// IsDisconnected
bool
RequestPortPool::IsDisconnected() const
{
return fDisconnected;
}
// AddPort
status_t
RequestPortPool::AddPort(RequestPort* port)
{
if (!port)
return B_BAD_VALUE;
PoolLocker _(this);
// resize the port array
PortAcquirationInfo* ports = (PortAcquirationInfo*)realloc(fPorts,
(fPortCount + 1) * sizeof(PortAcquirationInfo));
if (!ports)
return B_NO_MEMORY;
fPorts = ports;
// add the port as used port and let AcquirePort() free it
fPorts[fPortCount].port = port;
fPorts[fPortCount].owner = -1;
fPorts[fPortCount].count = 1;
fPortCount++;
ReleasePort(port);
return B_OK;
}
// AcquirePort
RequestPort*
RequestPortPool::AcquirePort()
{
// first check whether the thread does already own a port
thread_id thread = find_thread(NULL);
{
PoolLocker _(this);
if (fDisconnected)
return NULL;
for (int32 i = fFreePorts; i < fPortCount; i++) {
PortAcquirationInfo& info = fPorts[i];
if (info.owner == thread) {
info.count++;
return info.port;
}
}
}
// the thread doesn't own a port yet, find a free one
status_t error = acquire_sem(fFreePortSemaphore);
if (error != B_OK)
return NULL;
PoolLocker _(this);
if (fDisconnected)
return NULL;
if (fFreePorts < 1) {
FATAL(("Inconsistent request port pool: We acquired the free port "
"semaphore, but there are no free ports.\n"));
return NULL;
}
PortAcquirationInfo& info = fPorts[--fFreePorts];
info.owner = find_thread(NULL);
info.count = 1;
return info.port;
}
// ReleasePort
void
RequestPortPool::ReleasePort(RequestPort* port)
{
if (!port)
return;
PoolLocker _(this);
// find the port
for (int32 i = fFreePorts; i < fPortCount; i++) {
PortAcquirationInfo& info = fPorts[i];
if (info.port == port) {
if (--info.count == 0) {
// swap with first used port
if (i != fFreePorts) {
fPorts[i] = fPorts[fFreePorts];
fPorts[fFreePorts].port = port;
}
fFreePorts++;
release_sem(fFreePortSemaphore);
}
if (port->InitCheck() != B_OK)
fDisconnected = true;
return;
}
}
WARN(("RequestPortPool::ReleasePort(%p): port not found\n", port));
// Not found!
}
@@ -0,0 +1,48 @@
// RequestPortPool.h
#ifndef USERLAND_FS_REQUEST_PORT_POOL_H
#define USERLAND_FS_REQUEST_PORT_POOL_H
#include <OS.h>
#include "Locker.h"
namespace UserlandFSUtil {
class RequestPort;
}
using UserlandFSUtil::RequestPort;
class RequestPortPool : public Locker {
public:
RequestPortPool();
~RequestPortPool();
status_t InitCheck() const;
bool IsDisconnected() const;
status_t AddPort(RequestPort* port);
RequestPort* AcquirePort();
void ReleasePort(RequestPort* port);
private:
friend class KernelDebug;
struct PortAcquirationInfo {
RequestPort* port;
thread_id owner;
int32 count;
};
PortAcquirationInfo* fPorts;
int32 fPortCount;
int32 fFreePorts;
sem_id fFreePortSemaphore;
volatile bool fDisconnected;
};
#endif // USERLAND_FS_REQUEST_PORT_POOL_H
@@ -0,0 +1,254 @@
// Settings.cpp
#include <new>
#include <driver_settings.h>
#include "Debug.h"
#include "HashMap.h"
#include "IOCtlInfo.h"
#include "Settings.h"
static const char *kFSName = "userlandfs";
// IOCtlInfoMap
struct Settings::IOCtlInfoMap : public HashMap<HashKey32<int>, IOCtlInfo*> {
};
// _FindNextParameter
template<typename container_t>
static
const driver_parameter *
_FindNextParameter(const container_t *container, const char *name,
int32 &cookie)
{
const driver_parameter *parameter = NULL;
if (container) {
for (; !parameter && cookie < container->parameter_count; cookie++) {
const driver_parameter &param = container->parameters[cookie];
if (!strcmp(param.name, name))
parameter = &param;
}
}
return parameter;
}
// _GetParameterValue
template<typename container_t>
static
const char *
_GetParameterValue(const container_t *container, const char *name,
const char *unknownValue, const char *noArgValue)
{
if (container) {
for (int32 i = container->parameter_count - 1; i >= 0; i--) {
const driver_parameter &param = container->parameters[i];
if (!strcmp(param.name, name)) {
if (param.value_count > 0)
return param.values[0];
return noArgValue;
}
}
}
return unknownValue;
}
// contains
static inline
bool
contains(const char **array, size_t size, const char *value)
{
for (int32 i = 0; i < (int32)size; i++) {
if (!strcmp(array[i], value))
return true;
}
return false;
}
// _GetParameterValue
template<typename container_t>
static
bool
_GetParameterValue(const container_t *container, const char *name,
bool unknownValue, bool noArgValue)
{
// note: container may be NULL
const char unknown = 0;
const char noArg = 0;
const char *value = _GetParameterValue(container, name, &unknown, &noArg);
if (value == &unknown)
return unknownValue;
if (value == &noArg)
return noArgValue;
const char *trueStrings[]
= { "1", "true", "yes", "on", "enable", "enabled" };
const char *falseStrings[]
= { "0", "false", "no", "off", "disable", "disabled" };
if (contains(trueStrings, sizeof(trueStrings) / sizeof(const char*),
value)) {
return true;
}
if (contains(falseStrings, sizeof(falseStrings) / sizeof(const char*),
value)) {
return false;
}
return unknownValue;
}
// _GetParameterValue
template<typename container_t>
static
int
_GetParameterValue(const container_t *container, const char *name,
int unknownValue, int noArgValue)
{
// note: container may be NULL
const char unknown = 0;
const char noArg = 0;
const char *value = _GetParameterValue(container, name, &unknown, &noArg);
if (value == &unknown)
return unknownValue;
if (value == &noArg)
return noArgValue;
return atoi(value);
}
// _FindFSParameter
static
const driver_parameter *
_FindFSParameter(const driver_settings *settings, const char *name)
{
if (settings) {
int32 cookie = 0;
while (const driver_parameter *parameter
= _FindNextParameter(settings, "file_system", cookie)) {
PRINT((" found file_system parameter\n"));
if (parameter->value_count > 0)
PRINT((" value: `%s'\n", parameter->values[0]));
if (parameter->value_count == 1
&& !strcmp(parameter->values[0], name)) {
return parameter;
}
}
}
return NULL;
}
// constructor
Settings::Settings()
: fIOCtlInfos(NULL)
{
}
// destructor
Settings::~Settings()
{
Unset();
}
// SetTo
status_t
Settings::SetTo(const char* fsName)
{
if (!fsName)
RETURN_ERROR(B_BAD_VALUE);
// unset
Unset();
// create the ioctl info map
fIOCtlInfos = new(nothrow) IOCtlInfoMap;
if (!fIOCtlInfos)
RETURN_ERROR(B_NO_MEMORY);
// load the driver settings and find the entry for the FS
void *settings = load_driver_settings(kFSName);
const driver_parameter *fsParameter = NULL;
const driver_settings *ds = get_driver_settings(settings);
if (!ds)
RETURN_ERROR(B_ENTRY_NOT_FOUND);
fsParameter = _FindFSParameter(ds, fsName);
// init the object and unload the settings
status_t error = B_OK;
if (fsParameter)
_Init(ds, fsParameter);
else
error = B_ENTRY_NOT_FOUND;
unload_driver_settings(settings);
return B_OK;
}
// Unset
void
Settings::Unset()
{
if (fIOCtlInfos) {
for (IOCtlInfoMap::Iterator it = fIOCtlInfos->GetIterator();
it.HasNext();) {
IOCtlInfoMap::Entry entry = it.Next();
delete entry.value;
}
delete fIOCtlInfos;
fIOCtlInfos = NULL;
}
}
// GetIOCtlInfo
const IOCtlInfo*
Settings::GetIOCtlInfo(int command) const
{
return (fIOCtlInfos ? fIOCtlInfos->Get(command) : NULL);
}
// Dump
void
Settings::Dump() const
{
PRINT(("Settings:\n"));
if (fIOCtlInfos) {
for (IOCtlInfoMap::Iterator it = fIOCtlInfos->GetIterator();
it.HasNext();) {
IOCtlInfoMap::Entry entry = it.Next();
IOCtlInfo* info = entry.value;
PRINT((" ioctl %d: buffer size: %ld, write buffer size: %ld\n",
info->command, info->bufferSize, info->writeBufferSize));
}
}
}
// _Init
status_t
Settings::_Init(const driver_settings *settings,
const driver_parameter *fsParams)
{
PRINT(("Settings::_Init(%p, %p)\n", settings, fsParams));
status_t error = B_OK;
int32 cookie = 0;
while (const driver_parameter *parameter
= _FindNextParameter(fsParams, "ioctl", cookie)) {
if (parameter->value_count == 1) {
int command = atoi(parameter->values[0]);
if (command > 0) {
IOCtlInfo* info = fIOCtlInfos->Remove(command);
if (!info) {
info = new(nothrow) IOCtlInfo;
if (!info)
RETURN_ERROR(B_NO_MEMORY);
}
info->command = command;
info->bufferSize
= _GetParameterValue(parameter, "buffer_size", 0, 0);
info->writeBufferSize
= _GetParameterValue(parameter, "write_buffer_size", 0, 0);
info->isBuffer = _GetParameterValue(parameter, "is_buffer",
false, false);
error = fIOCtlInfos->Put(command, info);
if (error != B_OK) {
delete info;
return error;
}
}
}
}
PRINT(("Settings::_Init() done: %s\n", strerror(error)));
return error;
}
@@ -0,0 +1,35 @@
// Settings.h
#ifndef USERLAND_FS_SETTINGS_H
#define USERLAND_FS_SETTINGS_H
#include <SupportDefs.h>
struct driver_settings;
struct driver_parameter;
struct IOCtlInfo;
// Settings
class Settings {
public:
Settings();
~Settings();
status_t SetTo(const char *fsName);
void Unset();
const IOCtlInfo* GetIOCtlInfo(int command) const;
void Dump() const;
private:
status_t _Init(const driver_settings *settings,
const driver_parameter *fsParams);
private:
struct IOCtlInfoMap;
IOCtlInfoMap* fIOCtlInfos;
};
#endif // USERLAND_FS_SETTINGS_H
@@ -0,0 +1,258 @@
// UserlandFS.cpp
#include <KernelExport.h>
#include "AutoLocker.h"
#include "Compatibility.h"
#include "Debug.h"
#include "DispatcherDefs.h"
#include "FileSystem.h"
#include "KernelDebug.h"
#include "RequestPort.h"
#include "Requests.h"
#include "UserlandFS.h"
typedef AutoLocker<UserlandFS::FileSystemMap> FileSystemLocker;
UserlandFS* volatile UserlandFS::sUserlandFS = NULL;
spinlock UserlandFS::sUserlandFSLock = 0;
vint32 UserlandFS::sMountedFileSystems = 0;
// constructor
UserlandFS::UserlandFS()
: LazyInitializable(),
fPort(NULL),
fFileSystems(NULL),
fDebuggerCommandsAdded(false)
{
// beware what you do here: the caller holds a spin lock
}
// destructor
UserlandFS::~UserlandFS()
{
PRINT(("UserlandFS::~UserlandFS()\n"))
if (fPort) {
// send a disconnect request
RequestAllocator allocator(fPort->GetPort());
UFSDisconnectRequest* request;
if (AllocateRequest(allocator, &request) == B_OK) {
if (fPort->SendRequest(&allocator) != B_OK)
PRINT((" failed to send disconnect request\n"));
} else
PRINT((" failed to allocate disconnect request\n"));
delete fPort;
} else
PRINT((" no port\n"));
delete fFileSystems;
if (fDebuggerCommandsAdded)
KernelDebug::RemoveDebuggerCommands();
}
// RegisterUserlandFS
status_t
UserlandFS::RegisterUserlandFS(UserlandFS** _userlandFS)
{
// first check, if there's already an instance
bool create = false;
cpu_status cpuStatus = disable_interrupts();
acquire_spinlock(&sUserlandFSLock);
if (sUserlandFS)
sMountedFileSystems++;
else
create = true;
release_spinlock(&sUserlandFSLock);
restore_interrupts(cpuStatus);
// if there's not, create a new
status_t error = B_OK;
if (create) {
// first create an instance
// Note, that we can't even construct a LazyInitializable with a
// spinlock being held, since it allocates a semaphore, which may
// allocate memory, which will acquire a semaphore.
UserlandFS* userlandFS = new(nothrow) UserlandFS;
if (userlandFS) {
// now set the instance unless someone else beat us to it
bool deleteInstance = false;
cpu_status cpuStatus = disable_interrupts();
acquire_spinlock(&sUserlandFSLock);
sMountedFileSystems++;
if (sUserlandFS)
deleteInstance = true;
else
sUserlandFS = userlandFS;
release_spinlock(&sUserlandFSLock);
restore_interrupts(cpuStatus);
// delete the new instance, if there was one already
if (deleteInstance)
delete userlandFS;
} else
error = B_NO_MEMORY;
}
if (error != B_OK)
return error;
// init the thing, if necessary
error = sUserlandFS->Access();
if (error == B_OK)
*_userlandFS = sUserlandFS;
else
UnregisterUserlandFS();
return error;
}
// UnregisterUserlandFS
void
UserlandFS::UnregisterUserlandFS()
{
cpu_status cpuStatus = disable_interrupts();
acquire_spinlock(&sUserlandFSLock);
--sMountedFileSystems;
UserlandFS* userlandFS = NULL;
if (sMountedFileSystems == 0 && sUserlandFS) {
userlandFS = sUserlandFS;
sUserlandFS = NULL;
}
release_spinlock(&sUserlandFSLock);
restore_interrupts(cpuStatus);
// delete, if the last FS has been unmounted
if (userlandFS) {
userlandFS->~UserlandFS();
delete[] (uint8*)userlandFS;
}
}
// GetUserlandFS
UserlandFS*
UserlandFS::GetUserlandFS()
{
return sUserlandFS;
}
// RegisterFileSystem
status_t
UserlandFS::RegisterFileSystem(const char* name, FileSystem** _fileSystem)
{
// check initialization and parameters
if (InitCheck() != B_OK)
return InitCheck();
if (!name || !_fileSystem)
return B_BAD_VALUE;
// check, if we do already know this file system, and create it, if not
FileSystem* fileSystem;
{
FileSystemLocker _(fFileSystems);
fileSystem = fFileSystems->Get(name);
if (fileSystem) {
fileSystem->AddReference();
} else {
status_t error;
fileSystem = new(nothrow) FileSystem(name, fPort, &error);
if (!fileSystem)
return B_NO_MEMORY;
if (error == B_OK)
error = fFileSystems->Put(name, fileSystem);
if (error != B_OK) {
delete fileSystem;
return error;
}
}
}
// prepare the file system
status_t error = fileSystem->Access();
if (error != B_OK) {
UnregisterFileSystem(fileSystem);
return error;
}
*_fileSystem = fileSystem;
return error;
}
// UnregisterFileSystem
status_t
UserlandFS::UnregisterFileSystem(FileSystem* fileSystem)
{
if (!fileSystem)
return B_BAD_VALUE;
// find the FS and decrement its reference counter
bool deleteFS = false;
{
FileSystemLocker _(fFileSystems);
fileSystem = fFileSystems->Get(fileSystem->GetName());
if (!fileSystem)
return B_BAD_VALUE;
deleteFS = fileSystem->RemoveReference();
if (deleteFS)
fFileSystems->Remove(fileSystem->GetName());
}
// delete the FS, if the last reference has been removed
if (deleteFS)
delete fileSystem;
return B_OK;
}
// CountFileSystems
int32
UserlandFS::CountFileSystems() const
{
return fFileSystems->Size();
}
// FirstTimeInit
status_t
UserlandFS::FirstTimeInit()
{
// add debugger commands
KernelDebug::AddDebuggerCommands();
fDebuggerCommandsAdded = true;
// create file system map
fFileSystems = new(nothrow) FileSystemMap;
if (!fFileSystems)
RETURN_ERROR(B_NO_MEMORY);
status_t error = fFileSystems->InitCheck();
if (error != B_OK)
RETURN_ERROR(error);
// find the dispatcher ports
port_id port = find_port(kUserlandFSDispatcherPortName);
if (port < 0)
RETURN_ERROR(B_ERROR);
port_id replyPort = find_port(kUserlandFSDispatcherReplyPortName);
if (replyPort < 0)
RETURN_ERROR(B_ERROR);
// create a reply port
// send a connection request
error = write_port(port, UFS_DISPATCHER_CONNECT, NULL, 0);
if (error != B_OK)
RETURN_ERROR(error);
// receive the reply
int32 replyCode;
Port::Info portInfo;
ssize_t bytesRead = read_port(replyPort, &replyCode, &portInfo,
sizeof(Port::Info));
if (bytesRead < 0)
RETURN_ERROR(bytesRead);
if (replyCode != UFS_DISPATCHER_CONNECT_ACK)
RETURN_ERROR(B_BAD_DATA);
if (bytesRead != sizeof(Port::Info))
RETURN_ERROR(B_BAD_DATA);
// create a request port
fPort = new(nothrow) RequestPort(&portInfo);
if (!fPort)
RETURN_ERROR(B_NO_MEMORY);
if ((error = fPort->InitCheck()) != B_OK)
RETURN_ERROR(error);
RETURN_ERROR(error);
}
@@ -0,0 +1,54 @@
// UserlandFS.h
#ifndef USERLAND_FS_H
#define USERLAND_FS_H
#include <SupportDefs.h>
#include "HashMap.h"
#include "LazyInitializable.h"
#include "String.h"
namespace UserlandFSUtil {
class RequestPort;
}
using UserlandFSUtil::RequestPort;
class FileSystem;
class UserlandFS : public LazyInitializable {
private:
UserlandFS();
~UserlandFS();
public:
static status_t RegisterUserlandFS(UserlandFS** userlandFS);
static void UnregisterUserlandFS();
static UserlandFS* GetUserlandFS();
status_t RegisterFileSystem(const char* name,
FileSystem** fileSystem);
status_t UnregisterFileSystem(FileSystem* fileSystem);
int32 CountFileSystems() const;
protected:
virtual status_t FirstTimeInit();
private:
friend class KernelDebug;
typedef SynchronizedHashMap<String, FileSystem*> FileSystemMap;
static UserlandFS* volatile sUserlandFS;
static spinlock sUserlandFSLock;
static vint32 sMountedFileSystems;
RequestPort* fPort;
FileSystemMap* fFileSystems;
bool fDebuggerCommandsAdded;
};
#endif // USERLAND_FS_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,207 @@
// Volume.h
#ifndef USERLAND_FS_VOLUME_H
#define USERLAND_FS_VOLUME_H
#include <fsproto.h>
#include "Referencable.h"
namespace UserlandFSUtil {
class Request;
class RequestAllocator;
class RequestHandler;
}
using UserlandFSUtil::Request;
using UserlandFSUtil::RequestAllocator;
using UserlandFSUtil::RequestHandler;
class FileSystem;
struct userlandfs_ioctl;
class Volume : public Referencable {
public:
Volume(FileSystem* fileSystem, nspace_id id);
~Volume();
FileSystem* GetFileSystem() const;
nspace_id GetID() const;
void* GetUserlandVolume() const;
vnode_id GetRootID() const;
bool IsMounting() const;
// client methods
status_t GetVNode(vnode_id vnid, void** node);
status_t PutVNode(vnode_id vnid);
status_t NewVNode(vnode_id vnid, void* node);
status_t RemoveVNode(vnode_id vnid);
status_t UnremoveVNode(vnode_id vnid);
status_t IsVNodeRemoved(vnode_id vnid);
// FS
status_t Mount(const char* device, ulong flags,
const char* parameters, int32 len);
status_t Unmount();
status_t Sync();
status_t ReadFSStat(fs_info* info);
status_t WriteFSStat(struct fs_info* info, long mask);
// vnodes
status_t ReadVNode(vnode_id vnid, char reenter,
void** node);
status_t WriteVNode(void* node, char reenter);
status_t RemoveVNode(void* node, char reenter);
// nodes
status_t FSync(void* node);
status_t ReadStat(void* node, struct stat* st);
status_t WriteStat(void* node, struct stat *st,
long mask);
status_t Access(void* node, int mode);
// files
status_t Create(void* dir, const char* name,
int openMode, int mode, vnode_id* vnid,
void** cookie);
status_t Open(void* node, int openMode, void** cookie);
status_t Close(void* node, void* cookie);
status_t FreeCookie(void* node, void* cookie);
status_t Read(void* node, void* cookie, off_t pos,
void* buffer, size_t bufferSize,
size_t* bytesRead);
status_t Write(void* node, void* cookie, off_t pos,
const void* buffer, size_t bufferSize,
size_t* bytesWritten);
status_t IOCtl(void* node, void* cookie, int command,
void *buffer, size_t size);
status_t SetFlags(void* node, void* cookie, int flags);
status_t Select(void* node, void* cookie, uint8 event,
uint32 ref, selectsync* sync);
status_t Deselect(void* node, void* cookie, uint8 event,
selectsync* sync);
// hard links / symlinks
status_t Link(void* dir, const char* name, void* node);
status_t Unlink(void* dir, const char* name);
status_t Symlink(void* dir, const char* name,
const char* target);
status_t ReadLink(void* node, char* buffer,
size_t bufferSize, size_t* bytesRead);
status_t Rename(void* oldDir, const char* oldName,
void* newDir, const char* newName);
// directories
status_t MkDir(void* dir, const char* name, int mode);
status_t RmDir(void* dir, const char* name);
status_t OpenDir(void* node, void** cookie);
status_t CloseDir(void* node, void* cookie);
status_t FreeDirCookie(void* node, void* cookie);
status_t ReadDir(void* node, void* cookie,
void* buffer, size_t bufferSize,
int32 count, int32* countRead);
status_t RewindDir(void* node, void* cookie);
status_t Walk(void* dir, const char* entryName,
char** resolvedPath, vnode_id* vnid);
// attributes
status_t OpenAttrDir(void* node, void** cookie);
status_t CloseAttrDir(void* node, void* cookie);
status_t FreeAttrDirCookie(void* node, void* cookie);
status_t ReadAttrDir(void* node, void* cookie,
void* buffer, size_t bufferSize,
int32 count, int32* countRead);
status_t RewindAttrDir(void* node, void* cookie);
status_t ReadAttr(void* node, const char* name,
int type, off_t pos, void* buffer,
size_t bufferSize, size_t* bytesRead);
status_t WriteAttr(void* node, const char* name,
int type, off_t pos, const void* buffer,
size_t bufferSize, size_t* bytesWritten);
status_t RemoveAttr(void* node, const char* name);
status_t RenameAttr(void* node, const char* oldName,
const char* newName);
status_t StatAttr(void* node, const char* name,
struct attr_info* attrInfo);
// indices
status_t OpenIndexDir(void** cookie);
status_t CloseIndexDir(void* cookie);
status_t FreeIndexDirCookie(void* cookie);
status_t ReadIndexDir(void* cookie, void* buffer,
size_t bufferSize, int32 count,
int32* countRead);
status_t RewindIndexDir(void* cookie);
status_t CreateIndex(const char* name, int type,
int flags);
status_t RemoveIndex(const char* name);
status_t RenameIndex(const char* oldName,
const char* newName);
status_t StatIndex(const char *name,
struct index_info* indexInfo);
// queries
status_t OpenQuery(const char* queryString,
ulong flags, port_id port, long token,
void** cookie);
status_t CloseQuery(void* cookie);
status_t FreeQueryCookie(void* cookie);
status_t ReadQuery(void* cookie, void* buffer,
size_t bufferSize, int32 count,
int32* countRead);
private:
status_t _Mount(const char* device, ulong flags,
const char* parameters, int32 len);
status_t _Unmount();
status_t _WriteVNode(void* node, char reenter);
status_t _Close(void* node, void* cookie);
status_t _FreeCookie(void* node, void* cookie);
status_t _CloseDir(void* node, void* cookie);
status_t _FreeDirCookie(void* node, void* cookie);
status_t _Walk(void* dir, const char* entryName,
char** resolvedPath, vnode_id* vnid);
status_t _CloseAttrDir(void* node, void* cookie);
status_t _FreeAttrDirCookie(void* node, void* cookie);
status_t _CloseIndexDir(void* cookie);
status_t _FreeIndexDirCookie(void* cookie);
status_t _CloseQuery(void* cookie);
status_t _FreeQueryCookie(void* cookie);
status_t _SendRequest(RequestPort* port,
RequestAllocator* allocator,
RequestHandler* handler, Request** reply);
status_t _SendReceiptAck(RequestPort* port);
void _IncrementVNodeCount(vnode_id vnid);
void _DecrementVNodeCount(vnode_id vnid);
status_t _InternalIOCtl(userlandfs_ioctl* buffer,
int32 bufferSize);
status_t _PutAllPendingVNodes();
private:
struct MountVNodeMap;
struct VNodeCountMap;
class AutoIncrementer;
FileSystem* fFileSystem;
nspace_id fID;
void* fUserlandVolume;
vnode_id fRootID;
void* fRootNode;
MountVNodeMap* fMountVNodes;
vint32 fOpenFiles;
vint32 fOpenDirectories;
vint32 fOpenAttributeDirectories;
vint32 fOpenIndexDirectories;
vint32 fOpenQueries;
VNodeCountMap* fVNodeCountMap;
volatile bool fVNodeCountingEnabled;
};
#endif // USERLAND_FS_VOLUME_H
@@ -0,0 +1,16 @@
/* cpp - C++ in the kernel
**
** Initial version by Axel Dörfler, [email protected]
** This file may be used under the terms of the OpenBeOS License.
*/
#include "kernel-cpp.h"
#include <KernelExport.h>
#include <stdio.h>
FILE * stderr = NULL;
extern "C" int fprintf(FILE *f, const char *format, ...) { return 0; }
extern "C" void abort() { panic("abort() called!"); }
@@ -0,0 +1,48 @@
#ifndef KERNEL_CPP_H
#define KERNEL_CPP_H
/* cpp - C++ in the kernel
**
** Initial version by Axel Dörfler, [email protected]
** This file may be used under the terms of the OpenBeOS License.
*/
#ifdef __cplusplus
#include <new>
#include <stdlib.h>
// Oh no! C++ in the kernel! Are you nuts?
//
// - no exceptions
// - (almost) no virtuals (well, the Query code now uses them)
// - it's basically only the C++ syntax, and type checking
// - since one tend to encapsulate everything in classes, it has a slightly
// higher memory overhead
// - nicer code
// - easier to maintain
inline void *operator new(size_t size, const nothrow_t&) throw()
{
return malloc(size);
}
inline void *operator new[](size_t size, const nothrow_t&) throw()
{
return malloc(size);
}
inline void operator delete(void *ptr)
{
free(ptr);
}
inline void operator delete[](void *ptr)
{
free(ptr);
}
#endif // __cplusplus
#endif /* KERNEL_CPP_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,34 @@
// AreaSupport.cpp
#include "AreaSupport.h"
// get_area_for_address
status_t
UserlandFSUtil::get_area_for_address(void* address, int32 size, area_id* area,
int32* offset, void** areaBaseAddress)
{
// check parameters
if (!area || !offset || size < 0)
return B_BAD_VALUE;
// catch NULL address case
if (!address) {
*area = -1;
*offset = 0;
return B_OK;
}
// get area and in-area offset
*area = area_for(address);
if (*area < 0)
return *area;
area_info areaInfo;
status_t error = get_area_info(*area, &areaInfo);
if (error != B_OK)
return error;
// check the size
*offset = (uint8*)address - (uint8*)areaInfo.address;
if (*offset + size > (int32)areaInfo.size)
return B_BAD_VALUE;
if (areaBaseAddress)
*areaBaseAddress = areaInfo.address;
return B_OK;
}
@@ -0,0 +1,6 @@
// DispatcherDefs.cpp
#include "DispatcherDefs.h"
const char* kUserlandFSDispatcherPortName = "userland fs dispatcher";
const char* kUserlandFSDispatcherReplyPortName = "userland fs dispatcher reply";
@@ -0,0 +1,203 @@
// Port.cpp
#include <new>
#include "AreaSupport.h"
#include "Compatibility.h"
#include "Port.h"
// minimal and maximal port size
static const int32 kMinPortSize = 1024; // 1 kB
static const int32 kMaxPortSize = 64 * 1024; // 64 kB
// constructor
Port::Port(int32 size)
: fBuffer(NULL),
fCapacity(0),
fMessageSize(0),
fInitStatus(B_NO_INIT),
fOwner(true)
{
// adjust size to be within the sane bounds
if (size < kMinPortSize)
size = kMinPortSize;
else if (size > kMaxPortSize)
size = kMaxPortSize;
// allocate the buffer
fBuffer = new(nothrow) uint8[size];
if (!fBuffer) {
fInitStatus = B_NO_MEMORY;
return;
}
// create the owner port
fInfo.owner_port = create_port(1, "port owner port");
if (fInfo.owner_port < 0) {
fInitStatus = fInfo.owner_port;
return;
}
// create the client port
fInfo.client_port = create_port(1, "port client port");
if (fInfo.client_port < 0) {
fInitStatus = fInfo.client_port;
return;
}
fInfo.size = size;
fCapacity = size;
fInitStatus = B_OK;
}
// constructor
Port::Port(const Info* info)
: fBuffer(NULL),
fCapacity(0),
fMessageSize(0),
fInitStatus(B_NO_INIT),
fOwner(false)
{
// check parameters
if (!info || info->owner_port < 0 || info->client_port < 0
|| info->size < kMinPortSize || info->size > kMaxPortSize) {
return;
}
// allocate the buffer
fBuffer = new(nothrow) uint8[info->size];
if (!fBuffer) {
fInitStatus = B_NO_MEMORY;
return;
}
// init the info
fInfo.owner_port = info->owner_port;
fInfo.client_port = info->client_port;
fInfo.size = info->size;
// init the other members
fCapacity = info->size;
fInitStatus = B_OK;
}
// destructor
Port::~Port()
{
Close();
delete[] fBuffer;
}
// Close
void
Port::Close()
{
if (fInitStatus != B_OK)
return;
fInitStatus = B_NO_INIT;
// delete the ports only if we are the owner
if (fOwner) {
if (fInfo.owner_port >= 0)
delete_port(fInfo.owner_port);
if (fInfo.client_port >= 0)
delete_port(fInfo.client_port);
}
fInfo.owner_port = -1;
fInfo.client_port = -1;
}
// InitCheck
status_t
Port::InitCheck() const
{
return fInitStatus;
}
// GetInfo
const Port::Info*
Port::GetInfo() const
{
return &fInfo;
}
// GetBuffer
void*
Port::GetBuffer() const
{
return fBuffer;
}
// GetCapacity
int32
Port::GetCapacity() const
{
return fCapacity;
}
// GetMessage
void*
Port::GetMessage() const
{
return (fInitStatus == B_OK && fMessageSize > 0 ? fBuffer : NULL);
}
// GetMessageSize
int32
Port::GetMessageSize() const
{
return (fInitStatus == B_OK ? fMessageSize : 0);
}
// Send
status_t
Port::Send(int32 size)
{
if (fInitStatus != B_OK)
return fInitStatus;
if (size <= 0 || size > fCapacity)
return B_BAD_VALUE;
fMessageSize = 0;
port_id port = (fOwner ? fInfo.client_port : fInfo.owner_port);
status_t error;
do {
error = write_port(port, 0, fBuffer, size);
} while (error == B_INTERRUPTED);
return (fInitStatus = error);
}
// SendAndReceive
status_t
Port::SendAndReceive(int32 size)
{
status_t error = Send(size);
if (error != B_OK)
return error;
return Receive();
}
// Receive
status_t
Port::Receive(bigtime_t timeout)
{
if (fInitStatus != B_OK)
return fInitStatus;
port_id port = (fOwner ? fInfo.owner_port : fInfo.client_port);
status_t error = B_OK;
do {
int32 code;
ssize_t bytesRead;
if (timeout >= 0) {
bytesRead = read_port_etc(port, &code, fBuffer, fCapacity,
B_RELATIVE_TIMEOUT, timeout);
} else
bytesRead = read_port(port, &code, fBuffer, fCapacity);
if (bytesRead < 0)
error = bytesRead;
else
fMessageSize = bytesRead;
} while (error == B_INTERRUPTED);
if (error == B_TIMED_OUT || error == B_WOULD_BLOCK) {
return error;
}
if (error != B_OK)
return (fInitStatus = error);
if (fMessageSize <= 0 || fMessageSize > fCapacity) {
fMessageSize = 0;
return B_BAD_DATA;
}
return B_OK;
}
@@ -0,0 +1,54 @@
// Request.cpp
#include "Request.h"
// Address
// constructor
Address::Address()
: fSize(0)
{
fUnrelocated.area = -1;
fUnrelocated.offset = 0;
}
// SetTo
void
Address::SetTo(area_id area, int32 offset, int32 size)
{
fUnrelocated.area = area;
fUnrelocated.offset = offset;
fSize = size;
}
// Request
// constructor
Request::Request(uint32 type)
: fType(type)
{
}
// GetType
uint32
Request::GetType() const
{
return fType;
}
// Check
status_t
Request::Check() const
{
return B_OK;
}
// GetAddressInfos
status_t
Request::GetAddressInfos(AddressInfo* infos, int32* count)
{
*count = 0;
return B_OK;
}
@@ -0,0 +1,289 @@
// RequestAllocator.cpp
#include <new>
#include "AreaSupport.h"
#include "Compatibility.h"
#include "Debug.h"
#include "Port.h"
#include "RequestAllocator.h"
// constructor
RequestAllocator::RequestAllocator(Port* port)
: fError(B_NO_INIT),
fPort(NULL),
fRequest(NULL),
fRequestSize(0),
fAllocatedAreaCount(0),
fDeferredInitInfoCount(0),
fRequestInPortBuffer(false)
{
Init(port);
}
// destructor
RequestAllocator::~RequestAllocator()
{
Uninit();
}
// Init
status_t
RequestAllocator::Init(Port* port)
{
Uninit();
if (port) {
fPort = port;
fError = fPort->InitCheck();
}
return fError;
}
// Uninit
void
RequestAllocator::Uninit()
{
if (!fRequestInPortBuffer)
delete[] (uint8*)fRequest;
for (int32 i = 0; i < fAllocatedAreaCount; i++)
delete_area(fAllocatedAreas[i]);
fAllocatedAreaCount = 0;
for (int32 i = 0; i < fDeferredInitInfoCount; i++) {
if (fDeferredInitInfos[i].inPortBuffer)
delete[] fDeferredInitInfos[i].data;
}
fDeferredInitInfoCount = 0;
fError = B_NO_INIT;
fPort = NULL;
fRequest = NULL;
fRequestSize = 0;
}
// Error
status_t
RequestAllocator::Error() const
{
return fError;
}
// FinishDeferredInit
void
RequestAllocator::FinishDeferredInit()
{
if (fError != B_OK)
return;
for (int32 i = 0; i < fDeferredInitInfoCount; i++) {
DeferredInitInfo& info = fDeferredInitInfos[i];
if (info.inPortBuffer) {
if (info.size > 0)
memcpy((uint8*)fRequest + info.offset, info.data, info.size);
delete[] info.data;
}
PRINT(("RequestAllocator::FinishDeferredInit(): area: %ld, "
"offset: %ld, size: %ld\n", info.area, info.offset, info.size));
info.target->SetTo(info.area, info.offset, info.size);
}
fDeferredInitInfoCount = 0;
}
// AllocateRequest
status_t
RequestAllocator::AllocateRequest(int32 size)
{
if (fError != B_OK)
RETURN_ERROR(fError);
if (size < (int32)sizeof(Request) || size > fPort->GetCapacity())
RETURN_ERROR(fError = B_BAD_VALUE);
fRequest = (Request*)fPort->GetBuffer();
fRequestSize = size;
fRequestInPortBuffer = true;
return B_OK;
}
// ReadRequest
status_t
RequestAllocator::ReadRequest()
{
if (fError != B_OK)
RETURN_ERROR(fError);
if (fPort->GetMessageSize() < (int32)sizeof(Request))
RETURN_ERROR(fError = B_BAD_DATA);
// clone the request
fRequest = (Request*)new(nothrow) uint8[fPort->GetMessageSize()];
if (!fRequest)
RETURN_ERROR(fError = B_NO_MEMORY);
memcpy(fRequest, fPort->GetMessage(), fPort->GetMessageSize());
fRequestSize = fPort->GetMessageSize();
fRequestInPortBuffer = false;
// relocate the request
fError = relocate_request(fRequest, fRequestSize, fAllocatedAreas,
&fAllocatedAreaCount);
RETURN_ERROR(fError);
}
// GetRequest
Request*
RequestAllocator::GetRequest() const
{
return fRequest;
}
// GetRequestSize
int32
RequestAllocator::GetRequestSize() const
{
return fRequestSize;
}
// AllocateAddress
status_t
RequestAllocator::AllocateAddress(Address& address, int32 size, int32 align,
void** data, bool deferredInit)
{
if (fError != B_OK)
return fError;
if (!fRequest)
RETURN_ERROR(B_NO_INIT);
if (size < 0)
RETURN_ERROR(B_BAD_VALUE);
if (fDeferredInitInfoCount >= MAX_REQUEST_ADDRESS_COUNT)
RETURN_ERROR(B_BAD_VALUE);
// fix the alignment -- valid is 1, 2, 4, 8
if (align <= 0 || size == 0 || (align & 0x1))
align = 1;
else if (align & 0x2)
align = 2;
else if (align & 0x4)
align = 4;
else
align = 8;
// check address location
// Currently we only support relocation of addresses inside the
// port buffer.
int32 addressOffset = (uint8*)&address - (uint8*)fRequest;
if (addressOffset < (int32)sizeof(Request)
|| addressOffset + (int32)sizeof(Address) > fRequestSize) {
RETURN_ERROR(B_BAD_VALUE);
}
// get the next free aligned offset in the port buffer
int32 offset = (fRequestSize + align - 1) / align * align;
// allocate the data
if (offset + size <= fPort->GetCapacity()) {
// there's enough free space in the port buffer
fRequestSize = offset + size;
if (deferredInit) {
DeferredInitInfo& info
= fDeferredInitInfos[fDeferredInitInfoCount];
if (size > 0) {
info.data = new(nothrow) uint8[size];
if (!info.data)
RETURN_ERROR(B_NO_MEMORY);
} else
info.data = NULL;
info.area = -1;
info.offset = offset;
info.size = size;
info.inPortBuffer = true;
info.target = &address;
*data = info.data;
fDeferredInitInfoCount++;
} else {
*data = (uint8*)fRequest + offset;
address.SetTo(-1, offset, size);
}
} else {
// not enough room in the port's buffer: we need to allocate an area
if (fAllocatedAreaCount >= MAX_REQUEST_ADDRESS_COUNT)
RETURN_ERROR(B_ERROR);
int32 areaSize = (size + B_PAGE_SIZE - 1) / B_PAGE_SIZE * B_PAGE_SIZE;
area_id area = create_area("request data", data,
#ifdef _KERNEL_MODE
B_ANY_KERNEL_ADDRESS,
#else
B_ANY_ADDRESS,
#endif
areaSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (area < 0)
RETURN_ERROR(area);
fAllocatedAreas[fAllocatedAreaCount++] = area;
if (deferredInit) {
DeferredInitInfo& info
= fDeferredInitInfos[fDeferredInitInfoCount];
info.data = NULL;
info.area = area;
info.offset = 0;
info.size = size;
info.inPortBuffer = false;
info.target = &address;
fDeferredInitInfoCount++;
PRINT((" RequestAllocator::AllocateAddress(): deferred allocated area: "
"%ld, size: %ld (%ld), data: %p\n", area, size, areaSize, *data));
} else
address.SetTo(area, 0, size);
}
return B_OK;
}
// AllocateData
status_t
RequestAllocator::AllocateData(Address& address, const void* data, int32 size,
int32 align, bool deferredInit)
{
void* destination;
status_t error = AllocateAddress(address, size, align, &destination,
deferredInit);
if (error != B_OK)
return error;
if (size > 0)
memcpy(destination, data, size);
return error;
}
// AllocateString
status_t
RequestAllocator::AllocateString(Address& address, const char* data,
bool deferredInit)
{
int32 size = (data ? strlen(data) + 1 : 0);
return AllocateData(address, data, size, 1, deferredInit);
}
// SetAddress
/*status_t
RequestAllocator::SetAddress(Address& address, void* data, int32 size)
{
if (fError != B_OK)
return fError;
if (!fRequest)
return (fError = B_NO_INIT);
// check address location
// Currently we only support relocation of addresses inside the
// port buffer.
int32 addressOffset = (uint8*)&address - (uint8*)fRequest;
if (addressOffset < (int32)sizeof(Request)
|| addressOffset + (int32)sizeof(Address) > fRequestSize) {
return (fError = B_BAD_VALUE);
}
// if data does itself lie within the port buffer, we store only the
// request relative offset
int32 inRequestOffset = (uint8*)data - (uint8*)fRequest;
if (!data) {
address.SetTo(-1, 0, 0);
} else if (inRequestOffset >= (int32)sizeof(Request)
&& inRequestOffset <= fRequestSize) {
if (inRequestOffset + size > fRequestSize)
return (fError = B_BAD_VALUE);
address.SetTo(-1, inRequestOffset, size);
} else {
// get the area and in-area offset for the address
area_id area;
int32 offset;
fError = get_area_for_address(data, size, &area, &offset);
if (fError != B_OK)
return fError;
// set the address
address.SetTo(area, offset, size);
}
return fError;
}*/
@@ -0,0 +1,30 @@
// RequestHandler.cpp
#include "RequestHandler.h"
// constructor
RequestHandler::RequestHandler()
: fPort(NULL),
fDone(false)
{
}
// destructor
RequestHandler::~RequestHandler()
{
}
// SetPort
void
RequestHandler::SetPort(RequestPort* port)
{
fPort = port;
}
// IsDone
bool
RequestHandler::IsDone() const
{
return fDone;
}
@@ -0,0 +1,204 @@
// RequestPort.cpp
#include <new>
#include "AutoDeleter.h"
#include "Debug.h"
#include "Request.h"
#include "RequestHandler.h"
#include "RequestPort.h"
// TODO: Limit the stacking of requests?
// AllocatorNode
struct RequestPort::AllocatorNode {
AllocatorNode(Port* port) : allocator(port), previous(NULL) {}
RequestAllocator allocator;
AllocatorNode* previous;
};
// constructor
RequestPort::RequestPort(int32 size)
: fPort(size),
fCurrentAllocatorNode(NULL)
{
}
// constructor
RequestPort::RequestPort(const Port::Info* info)
: fPort(info),
fCurrentAllocatorNode(NULL)
{
}
// destructor
RequestPort::~RequestPort()
{
while (fCurrentAllocatorNode)
_PopAllocator();
}
// Close
void
RequestPort::Close()
{
fPort.Close();
}
// InitCheck
status_t
RequestPort::InitCheck() const
{
return fPort.InitCheck();
}
// GetPort
Port*
RequestPort::GetPort()
{
return &fPort;
}
// GetPortInfo
const Port::Info*
RequestPort::GetPortInfo() const
{
return fPort.GetInfo();
}
// SendRequest
status_t
RequestPort::SendRequest(RequestAllocator* allocator)
{
// check initialization and parameters
if (InitCheck() != B_OK)
RETURN_ERROR(InitCheck());
if (!allocator || allocator->GetRequest() != fPort.GetBuffer()
|| allocator->GetRequestSize() < (int32)sizeof(Request)
|| allocator->GetRequestSize() > fPort.GetCapacity()) {
RETURN_ERROR(B_BAD_VALUE);
}
allocator->FinishDeferredInit();
//PRINT(("RequestPort::SendRequest(%lu)\n", allocator->GetRequest()->GetType()));
#if USER && !KERNEL_EMU
if (!is_userland_request(allocator->GetRequest()->GetType())) {
ERROR(("RequestPort::SendRequest(%lu): request is not a userland "
"request\n", allocator->GetRequest()->GetType()));
debugger("Request is not a userland request.");
}
#else
if (!is_kernel_request(allocator->GetRequest()->GetType())) {
ERROR(("RequestPort::SendRequest(%lu): request is not a userland "
"request\n", allocator->GetRequest()->GetType()));
debugger("Request is not a userland request.");
}
#endif
RETURN_ERROR(fPort.Send(allocator->GetRequestSize()));
}
// SendRequest
status_t
RequestPort::SendRequest(RequestAllocator* allocator,
RequestHandler* handler, Request** reply, bigtime_t timeout)
{
status_t error = SendRequest(allocator);
if (error != B_OK)
return error;
return HandleRequests(handler, reply, timeout);
}
// ReceiveRequest
//
// The caller is responsible for calling ReleaseRequest() with the request.
status_t
RequestPort::ReceiveRequest(Request** request, bigtime_t timeout)
{
// check initialization and parameters
if (InitCheck() != B_OK)
RETURN_ERROR(InitCheck());
if (!request)
RETURN_ERROR(B_BAD_VALUE);
// allocate a request allocator
AllocatorNode* node = new(nothrow) AllocatorNode(&fPort);
if (!node)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<AllocatorNode> deleter(node);
// receive the message
status_t error = fPort.Receive(timeout);
if (error != B_OK) {
if (error != B_TIMED_OUT && error != B_WOULD_BLOCK)
RETURN_ERROR(error);
return error;
}
// allocate the request
error = node->allocator.ReadRequest();
if (error != B_OK)
RETURN_ERROR(error);
// everything went fine: push the allocator
*request = node->allocator.GetRequest();
node->previous = fCurrentAllocatorNode;
fCurrentAllocatorNode = node;
deleter.Detach();
//PRINT(("RequestPort::RequestReceived(%lu)\n", (*request)->GetType()));
return B_OK;
}
// HandleRequests
//
// If request is not NULL, the caller is responsible for calling
// ReleaseRequest() with the request. If it is NULL, the request will already
// be gone, when the method returns.
status_t
RequestPort::HandleRequests(RequestHandler* handler, Request** request,
bigtime_t timeout)
{
// check initialization and parameters
if (InitCheck() != B_OK)
RETURN_ERROR(InitCheck());
if (!handler)
RETURN_ERROR(B_BAD_VALUE);
handler->SetPort(this);
Request* currentRequest = NULL;
do {
if (currentRequest)
ReleaseRequest(currentRequest);
status_t error = ReceiveRequest(&currentRequest, timeout);
if (error != B_OK)
return error;
// handle the request
error = handler->HandleRequest(currentRequest);
if (error != B_OK) {
ReleaseRequest(currentRequest);
RETURN_ERROR(error);
}
} while (!handler->IsDone());
if (request)
*request = currentRequest;
else
ReleaseRequest(currentRequest);
return B_OK;
}
// ReleaseRequest
void
RequestPort::ReleaseRequest(Request* request)
{
if (request && fCurrentAllocatorNode
&& request == fCurrentAllocatorNode->allocator.GetRequest()) {
_PopAllocator();
}
}
// _PopAllocator
void
RequestPort::_PopAllocator()
{
if (fCurrentAllocatorNode) {
AllocatorNode* node = fCurrentAllocatorNode->previous;
delete fCurrentAllocatorNode;
fCurrentAllocatorNode = node;
}
}
@@ -0,0 +1,869 @@
// Requests.cpp
#include <limits.h>
#include "Debug.h"
#include "Requests.h"
#define _ADD_ADDRESS(_address, _flags) \
if (*count >= MAX_REQUEST_ADDRESS_COUNT) \
return B_BAD_VALUE; \
infos[*count].address = &_address; \
infos[*count].flags = _flags; \
infos[(*count)++].max_size = LONG_MAX; // TODO:...
#define ADD_ADDRESS(address) _ADD_ADDRESS(address, 0)
#define ADD_STRING(address) _ADD_ADDRESS(address, ADDRESS_IS_STRING)
#define ADD_NON_NULL_ADDRESS(address) _ADD_ADDRESS(address, ADDRESS_NOT_NULL)
#define ADD_NON_NULL_STRING(address) \
_ADD_ADDRESS(address, (ADDRESS_IS_STRING | ADDRESS_NOT_NULL))
// FSConnectRequest
status_t
FSConnectRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(fsName);
return B_OK;
}
// FSConnectReply
status_t
FSConnectReply::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_ADDRESS(portInfos);
return B_OK;
}
// MountVolumeRequest
status_t
MountVolumeRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(cwd);
ADD_STRING(device);
ADD_STRING(parameters);
return B_OK;
}
// InitializeVolumeRequest
status_t
InitializeVolumeRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_STRING(device);
ADD_STRING(parameters);
return B_OK;
}
// CreateRequest
status_t
CreateRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// ReadReply
status_t
ReadReply::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_ADDRESS(buffer);
return B_OK;
}
// WriteRequest
status_t
WriteRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_ADDRESS(buffer);
return B_OK;
}
// IOCtlRequest
status_t
IOCtlRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_ADDRESS(buffer);
return B_OK;
}
// IOCtlReply
status_t
IOCtlReply::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_ADDRESS(buffer);
return B_OK;
}
// LinkRequest
status_t
LinkRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// UnlinkRequest
status_t
UnlinkRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// SymlinkRequest
status_t
SymlinkRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
ADD_NON_NULL_STRING(target);
return B_OK;
}
// ReadLinkReply
status_t
ReadLinkReply::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_STRING(buffer);
return B_OK;
}
// RenameRequest
status_t
RenameRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(oldName);
ADD_NON_NULL_STRING(newName);
return B_OK;
}
// MkDirRequest
status_t
MkDirRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// RmDirRequest
status_t
RmDirRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// ReadDirReply
status_t
ReadDirReply::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_ADDRESS(buffer);
return B_OK;
}
// WalkRequest
status_t
WalkRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(entryName);
return B_OK;
}
// WalkReply
status_t
WalkReply::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_STRING(resolvedPath);
return B_OK;
}
// ReadAttrDirReply
status_t
ReadAttrDirReply::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_ADDRESS(buffer);
return B_OK;
}
// ReadAttrRequest
status_t
ReadAttrRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// ReadAttrReply
status_t
ReadAttrReply::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_ADDRESS(buffer);
return B_OK;
}
// WriteAttrRequest
status_t
WriteAttrRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
ADD_ADDRESS(buffer);
return B_OK;
}
// RemoveAttrRequest
status_t
RemoveAttrRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// RenameAttrRequest
status_t
RenameAttrRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(oldName);
ADD_NON_NULL_STRING(newName);
return B_OK;
}
// StatAttrRequest
status_t
StatAttrRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// ReadIndexDirReply
status_t
ReadIndexDirReply::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_ADDRESS(buffer);
return B_OK;
}
// CreateIndexRequest
status_t
CreateIndexRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// RemoveIndexRequest
status_t
RemoveIndexRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// RenameIndexRequest
status_t
RenameIndexRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(oldName);
ADD_NON_NULL_STRING(newName);
return B_OK;
}
// StatIndexRequest
status_t
StatIndexRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// OpenQueryRequest
status_t
OpenQueryRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(queryString);
return B_OK;
}
// ReadQueryReply
status_t
ReadQueryReply::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_ADDRESS(buffer);
return B_OK;
}
// NotifyListenerRequest
status_t
NotifyListenerRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_STRING(name);
return B_OK;
}
// SendNotificationRequest
status_t
SendNotificationRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_STRING(name);
return B_OK;
}
// #pragma mark -
// RequestAddressInfoGetter
struct RequestAddressInfoGetter {
RequestAddressInfoGetter(AddressInfo* infos, int32* count)
: fInfos(infos),
fCount(count)
{
}
template<typename R> status_t operator()(R* request)
{
return request->GetAddressInfos(fInfos, fCount);
}
private:
AddressInfo* fInfos;
int32* fCount;
};
// get_request_address_infos
status_t
UserlandFSUtil::get_request_address_infos(Request* request, AddressInfo* infos,
int32* count)
{
if (!infos || !count)
return B_BAD_VALUE;
*count = 0;
RequestAddressInfoGetter task(infos, count);
return do_for_request(request, task);
}
// RequestChecker
struct RequestChecker {
template<typename R> status_t operator()(R* request)
{
return request->Check();
}
};
// check_request
status_t
UserlandFSUtil::check_request(Request* request)
{
RequestChecker task;
return do_for_request(request, task);
}
// is_error_reply
static inline
bool
is_error_reply(Request* request)
{
return false;
}
// is_error_reply
static inline
bool
is_error_reply(ReplyRequest* request)
{
return (request->error != B_OK);
}
// RequestRelocator
struct RequestRelocator {
RequestRelocator(int32 requestBufferSize, area_id* areas, int32* count)
: fRequestBufferSize(requestBufferSize),
fAreas(areas),
fAreaCount(count)
{
*fAreaCount = 0;
}
~RequestRelocator()
{
if (!fSuccess) {
for (int32 i = 0; i < *fAreaCount; i++)
delete_area(fAreas[i]);
}
}
template<typename R> status_t operator()(R* request)
{
// check the request buffer size
if (fRequestBufferSize < (int32)sizeof(R))
RETURN_ERROR(B_BAD_DATA);
// no need to relocate the addresses of a reply that indicates an error
if (is_error_reply(request)) {
fSuccess = true;
return B_OK;
}
// get the address infos
AddressInfo infos[MAX_REQUEST_ADDRESS_COUNT];
int32 count = 0;
status_t error = request->GetAddressInfos(infos, &count);
if (error != B_OK)
RETURN_ERROR(error);
// check and relocate the addresses
for (int32 i = 0; i < count; i++) {
// check
Address* address = infos[i].address;
int32 size = address->GetSize();
int32 offset = address->GetOffset();
//PRINT((" relocating address: area: %ld, offset: %ld, size: %ld...\n",
//address->GetArea(), offset, size));
if (offset < 0 || size < 0 || size > infos[i].max_size)
RETURN_ERROR(B_BAD_DATA);
if ((infos[i].flags & ADDRESS_NOT_NULL) && size == 0)
RETURN_ERROR(B_BAD_DATA);
// relocate
area_id area = address->GetArea();
if (area < 0) {
// data in the buffer itself
if (offset == 0 && size == 0) {
//PRINT((" -> relocated address: NULL\n"));
address->SetRelocatedAddress(NULL);
} else {
if (offset < (int32)sizeof(R)
|| offset + size > fRequestBufferSize) {
RETURN_ERROR(B_BAD_DATA);
}
//PRINT((" -> relocated address: %p\n", (uint8*)request + offset));
address->SetRelocatedAddress((uint8*)request + offset);
}
} else {
// clone the area
void* data;
area = clone_area("cloned request data", &data,
#ifdef _KERNEL_MODE
B_ANY_KERNEL_ADDRESS,
#else
B_ANY_ADDRESS,
#endif
B_READ_AREA, area);
if (area < 0)
RETURN_ERROR(area);
fAreas[(*fAreaCount)++] = area;
// check offset and size
area_info areaInfo;
error = get_area_info(area, &areaInfo);
if (error != B_OK)
RETURN_ERROR(error);
if (offset + size > (int32)areaInfo.size)
RETURN_ERROR(B_BAD_DATA);
//PRINT((" -> relocated address: %p\n", (uint8*)data + offset));
address->SetRelocatedAddress((uint8*)data + offset);
}
}
// finally let the request check its integrity
error = request->Check();
if (error != B_OK)
RETURN_ERROR(error);
fSuccess = true;
//PRINT(("RequestRelocator done: success\n"));
return B_OK;
}
private:
int32 fRequestBufferSize;
area_id* fAreas;
int32* fAreaCount;
bool fSuccess;
};
// relocate_request
status_t
UserlandFSUtil::relocate_request(Request* request, int32 requestBufferSize,
area_id* areas, int32* count)
{
if (!request || !areas || !count)
return B_BAD_VALUE;
RequestRelocator task(requestBufferSize, areas, count);
return do_for_request(request, task);
}
// is_kernel_request
bool
UserlandFSUtil::is_kernel_request(uint32 type)
{
switch (type) {
// kernel -> userland requests
// administrative
case UFS_DISCONNECT_REQUEST:
case FS_CONNECT_REQUEST:
return true;
case FS_CONNECT_REPLY:
return false;
// FS
case MOUNT_VOLUME_REQUEST:
case UNMOUNT_VOLUME_REQUEST:
case INITIALIZE_VOLUME_REQUEST:
case SYNC_VOLUME_REQUEST:
case READ_FS_STAT_REQUEST:
case WRITE_FS_STAT_REQUEST:
return true;
case MOUNT_VOLUME_REPLY:
case UNMOUNT_VOLUME_REPLY:
case INITIALIZE_VOLUME_REPLY:
case SYNC_VOLUME_REPLY:
case READ_FS_STAT_REPLY:
case WRITE_FS_STAT_REPLY:
return false;
// vnodes
case READ_VNODE_REQUEST:
case WRITE_VNODE_REQUEST:
case FS_REMOVE_VNODE_REQUEST:
return true;
case READ_VNODE_REPLY:
case WRITE_VNODE_REPLY:
case FS_REMOVE_VNODE_REPLY:
return false;
// nodes
case FSYNC_REQUEST:
case READ_STAT_REQUEST:
case WRITE_STAT_REQUEST:
case ACCESS_REQUEST:
return true;
case FSYNC_REPLY:
case READ_STAT_REPLY:
case WRITE_STAT_REPLY:
case ACCESS_REPLY:
return false;
// files
case CREATE_REQUEST:
case OPEN_REQUEST:
case CLOSE_REQUEST:
case FREE_COOKIE_REQUEST:
case READ_REQUEST:
case WRITE_REQUEST:
case IOCTL_REQUEST:
case SET_FLAGS_REQUEST:
case SELECT_REQUEST:
case DESELECT_REQUEST:
return true;
case CREATE_REPLY:
case OPEN_REPLY:
case CLOSE_REPLY:
case FREE_COOKIE_REPLY:
case READ_REPLY:
case WRITE_REPLY:
case IOCTL_REPLY:
case SET_FLAGS_REPLY:
case SELECT_REPLY:
case DESELECT_REPLY:
return false;
// hard links / symlinks
case LINK_REQUEST:
case UNLINK_REQUEST:
case SYMLINK_REQUEST:
case READ_LINK_REQUEST:
case RENAME_REQUEST:
return true;
case LINK_REPLY:
case UNLINK_REPLY:
case SYMLINK_REPLY:
case READ_LINK_REPLY:
case RENAME_REPLY:
return false;
// directories
case MKDIR_REQUEST:
case RMDIR_REQUEST:
case OPEN_DIR_REQUEST:
case CLOSE_DIR_REQUEST:
case FREE_DIR_COOKIE_REQUEST:
case READ_DIR_REQUEST:
case REWIND_DIR_REQUEST:
case WALK_REQUEST:
return true;
case MKDIR_REPLY:
case RMDIR_REPLY:
case OPEN_DIR_REPLY:
case CLOSE_DIR_REPLY:
case FREE_DIR_COOKIE_REPLY:
case READ_DIR_REPLY:
case REWIND_DIR_REPLY:
case WALK_REPLY:
return false;
// attributes
case OPEN_ATTR_DIR_REQUEST:
case CLOSE_ATTR_DIR_REQUEST:
case FREE_ATTR_DIR_COOKIE_REQUEST:
case READ_ATTR_DIR_REQUEST:
case REWIND_ATTR_DIR_REQUEST:
case READ_ATTR_REQUEST:
case WRITE_ATTR_REQUEST:
case REMOVE_ATTR_REQUEST:
case RENAME_ATTR_REQUEST:
case STAT_ATTR_REQUEST:
return true;
case OPEN_ATTR_DIR_REPLY:
case CLOSE_ATTR_DIR_REPLY:
case FREE_ATTR_DIR_COOKIE_REPLY:
case READ_ATTR_DIR_REPLY:
case REWIND_ATTR_DIR_REPLY:
case READ_ATTR_REPLY:
case WRITE_ATTR_REPLY:
case REMOVE_ATTR_REPLY:
case RENAME_ATTR_REPLY:
case STAT_ATTR_REPLY:
return false;
// indices
case OPEN_INDEX_DIR_REQUEST:
case CLOSE_INDEX_DIR_REQUEST:
case FREE_INDEX_DIR_COOKIE_REQUEST:
case READ_INDEX_DIR_REQUEST:
case REWIND_INDEX_DIR_REQUEST:
case CREATE_INDEX_REQUEST:
case REMOVE_INDEX_REQUEST:
case RENAME_INDEX_REQUEST:
case STAT_INDEX_REQUEST:
return true;
case OPEN_INDEX_DIR_REPLY:
case CLOSE_INDEX_DIR_REPLY:
case FREE_INDEX_DIR_COOKIE_REPLY:
case READ_INDEX_DIR_REPLY:
case REWIND_INDEX_DIR_REPLY:
case CREATE_INDEX_REPLY:
case REMOVE_INDEX_REPLY:
case RENAME_INDEX_REPLY:
case STAT_INDEX_REPLY:
return false;
// queries
case OPEN_QUERY_REQUEST:
case CLOSE_QUERY_REQUEST:
case FREE_QUERY_COOKIE_REQUEST:
case READ_QUERY_REQUEST:
return true;
case OPEN_QUERY_REPLY:
case CLOSE_QUERY_REPLY:
case FREE_QUERY_COOKIE_REPLY:
case READ_QUERY_REPLY:
return false;
// userland -> kernel requests
// notifications
case NOTIFY_LISTENER_REQUEST:
case NOTIFY_SELECT_EVENT_REQUEST:
case SEND_NOTIFICATION_REQUEST:
return false;
case NOTIFY_LISTENER_REPLY:
case NOTIFY_SELECT_EVENT_REPLY:
case SEND_NOTIFICATION_REPLY:
return true;
// vnodes
case GET_VNODE_REQUEST:
case PUT_VNODE_REQUEST:
case NEW_VNODE_REQUEST:
case REMOVE_VNODE_REQUEST:
case UNREMOVE_VNODE_REQUEST:
case IS_VNODE_REMOVED_REQUEST:
return false;
case GET_VNODE_REPLY:
case PUT_VNODE_REPLY:
case NEW_VNODE_REPLY:
case REMOVE_VNODE_REPLY:
case UNREMOVE_VNODE_REPLY:
case IS_VNODE_REMOVED_REPLY:
return true;
// general reply
case RECEIPT_ACK_REPLY:
return true;
default:
return false;
}
}
// is_userland_request
bool
UserlandFSUtil::is_userland_request(uint32 type)
{
switch (type) {
// kernel -> userland requests
// administrative
case UFS_DISCONNECT_REQUEST:
case FS_CONNECT_REQUEST:
return false;
case FS_CONNECT_REPLY:
return true;
// FS
case MOUNT_VOLUME_REQUEST:
case UNMOUNT_VOLUME_REQUEST:
case INITIALIZE_VOLUME_REQUEST:
case SYNC_VOLUME_REQUEST:
case READ_FS_STAT_REQUEST:
case WRITE_FS_STAT_REQUEST:
return false;
case MOUNT_VOLUME_REPLY:
case UNMOUNT_VOLUME_REPLY:
case INITIALIZE_VOLUME_REPLY:
case SYNC_VOLUME_REPLY:
case READ_FS_STAT_REPLY:
case WRITE_FS_STAT_REPLY:
return true;
// vnodes
case READ_VNODE_REQUEST:
case WRITE_VNODE_REQUEST:
case FS_REMOVE_VNODE_REQUEST:
return false;
case READ_VNODE_REPLY:
case WRITE_VNODE_REPLY:
case FS_REMOVE_VNODE_REPLY:
return true;
// nodes
case FSYNC_REQUEST:
case READ_STAT_REQUEST:
case WRITE_STAT_REQUEST:
case ACCESS_REQUEST:
return false;
case FSYNC_REPLY:
case READ_STAT_REPLY:
case WRITE_STAT_REPLY:
case ACCESS_REPLY:
return true;
// files
case CREATE_REQUEST:
case OPEN_REQUEST:
case CLOSE_REQUEST:
case FREE_COOKIE_REQUEST:
case READ_REQUEST:
case WRITE_REQUEST:
case IOCTL_REQUEST:
case SET_FLAGS_REQUEST:
case SELECT_REQUEST:
case DESELECT_REQUEST:
return false;
case CREATE_REPLY:
case OPEN_REPLY:
case CLOSE_REPLY:
case FREE_COOKIE_REPLY:
case READ_REPLY:
case WRITE_REPLY:
case IOCTL_REPLY:
case SET_FLAGS_REPLY:
case SELECT_REPLY:
case DESELECT_REPLY:
return true;
// hard links / symlinks
case LINK_REQUEST:
case UNLINK_REQUEST:
case SYMLINK_REQUEST:
case READ_LINK_REQUEST:
case RENAME_REQUEST:
return false;
case LINK_REPLY:
case UNLINK_REPLY:
case SYMLINK_REPLY:
case READ_LINK_REPLY:
case RENAME_REPLY:
return true;
// directories
case MKDIR_REQUEST:
case RMDIR_REQUEST:
case OPEN_DIR_REQUEST:
case CLOSE_DIR_REQUEST:
case FREE_DIR_COOKIE_REQUEST:
case READ_DIR_REQUEST:
case REWIND_DIR_REQUEST:
case WALK_REQUEST:
return false;
case MKDIR_REPLY:
case RMDIR_REPLY:
case OPEN_DIR_REPLY:
case CLOSE_DIR_REPLY:
case FREE_DIR_COOKIE_REPLY:
case READ_DIR_REPLY:
case REWIND_DIR_REPLY:
case WALK_REPLY:
return true;
// attributes
case OPEN_ATTR_DIR_REQUEST:
case CLOSE_ATTR_DIR_REQUEST:
case FREE_ATTR_DIR_COOKIE_REQUEST:
case READ_ATTR_DIR_REQUEST:
case REWIND_ATTR_DIR_REQUEST:
case READ_ATTR_REQUEST:
case WRITE_ATTR_REQUEST:
case REMOVE_ATTR_REQUEST:
case RENAME_ATTR_REQUEST:
case STAT_ATTR_REQUEST:
return false;
case OPEN_ATTR_DIR_REPLY:
case CLOSE_ATTR_DIR_REPLY:
case FREE_ATTR_DIR_COOKIE_REPLY:
case READ_ATTR_DIR_REPLY:
case REWIND_ATTR_DIR_REPLY:
case READ_ATTR_REPLY:
case WRITE_ATTR_REPLY:
case REMOVE_ATTR_REPLY:
case RENAME_ATTR_REPLY:
case STAT_ATTR_REPLY:
return true;
// indices
case OPEN_INDEX_DIR_REQUEST:
case CLOSE_INDEX_DIR_REQUEST:
case FREE_INDEX_DIR_COOKIE_REQUEST:
case READ_INDEX_DIR_REQUEST:
case REWIND_INDEX_DIR_REQUEST:
case CREATE_INDEX_REQUEST:
case REMOVE_INDEX_REQUEST:
case RENAME_INDEX_REQUEST:
case STAT_INDEX_REQUEST:
return false;
case OPEN_INDEX_DIR_REPLY:
case CLOSE_INDEX_DIR_REPLY:
case FREE_INDEX_DIR_COOKIE_REPLY:
case READ_INDEX_DIR_REPLY:
case REWIND_INDEX_DIR_REPLY:
case CREATE_INDEX_REPLY:
case REMOVE_INDEX_REPLY:
case RENAME_INDEX_REPLY:
case STAT_INDEX_REPLY:
return true;
// queries
case OPEN_QUERY_REQUEST:
case CLOSE_QUERY_REQUEST:
case FREE_QUERY_COOKIE_REQUEST:
case READ_QUERY_REQUEST:
return false;
case OPEN_QUERY_REPLY:
case CLOSE_QUERY_REPLY:
case FREE_QUERY_COOKIE_REPLY:
case READ_QUERY_REPLY:
return true;
// userland -> kernel requests
// notifications
case NOTIFY_LISTENER_REQUEST:
case NOTIFY_SELECT_EVENT_REQUEST:
case SEND_NOTIFICATION_REQUEST:
return true;
case NOTIFY_LISTENER_REPLY:
case NOTIFY_SELECT_EVENT_REPLY:
case SEND_NOTIFICATION_REPLY:
return false;
// vnodes
case GET_VNODE_REQUEST:
case PUT_VNODE_REQUEST:
case NEW_VNODE_REQUEST:
case REMOVE_VNODE_REQUEST:
case UNREMOVE_VNODE_REQUEST:
case IS_VNODE_REMOVED_REQUEST:
return true;
case GET_VNODE_REPLY:
case PUT_VNODE_REPLY:
case NEW_VNODE_REPLY:
case REMOVE_VNODE_REPLY:
case UNREMOVE_VNODE_REPLY:
case IS_VNODE_REMOVED_REPLY:
return false;
// general reply
case RECEIPT_ACK_REPLY:
return true;
default:
return false;
}
}
@@ -0,0 +1,39 @@
// SingleReplyRequestHandler.cpp
#include "Compatibility.h"
#include "Debug.h"
#include "Request.h"
#include "SingleReplyRequestHandler.h"
// constructor
SingleReplyRequestHandler::SingleReplyRequestHandler()
: RequestHandler(),
fAcceptAnyRequest(true),
fExpectedReply(0)
{
}
// constructor
SingleReplyRequestHandler::SingleReplyRequestHandler(uint32 expectedReply)
: RequestHandler(),
fAcceptAnyRequest(false),
fExpectedReply(expectedReply)
{
}
// HandleRequest
status_t
SingleReplyRequestHandler::HandleRequest(Request* request)
{
if (!fAcceptAnyRequest && request->GetType() != fExpectedReply) {
PRINT(("SingleReplyRequestHandler::HandleRequest(): unexpected request: %lu "
"expected was: %lu\n", request->GetType(), fExpectedReply));
#if USER
debugger("SingleReplyRequestHandler::HandleRequest(): unexpected request!");
#endif
return B_BAD_DATA;
}
fDone = true;
return B_OK;
}
@@ -0,0 +1,6 @@
// userlandfs_ioctl.cpp
#include "userlandfs_ioctl.h"
const char kUserlandFSIOCtlMagic[USERLAND_IOCTL_MAGIC_LENGTH]
= "userlandfs mAGiC666";
@@ -0,0 +1,135 @@
// FSInfo.h
#ifndef USERLAND_FS_FS_INFO_H
#define USERLAND_FS_FS_INFO_H
#include <new>
#include <string.h>
#include <Message.h>
#include "Port.h"
#include "String.h"
namespace UserlandFS {
// FSInfo
class FSInfo {
public:
FSInfo()
: fInfos(NULL),
fCount(0)
{
}
FSInfo(const char* fsName, const Port::Info* infos, int32 count)
: fName(),
fInfos(NULL),
fCount(0)
{
SetTo(fsName, infos, count);
}
FSInfo(const BMessage* message)
: fName(),
fInfos(NULL),
fCount(0)
{
SetTo(message);
}
FSInfo(const FSInfo& other)
: fName(),
fInfos(NULL),
fCount(0)
{
SetTo(other.GetName(), other.fInfos, other.fCount);
}
~FSInfo()
{
Unset();
}
status_t SetTo(const char* fsName, const Port::Info* infos, int32 count)
{
Unset();
if (!fsName || !infos || count <= 0)
return B_BAD_VALUE;
if (!fName.SetTo(fsName))
return B_NO_MEMORY;
fInfos = new(nothrow) Port::Info[count];
if (!fInfos)
return B_NO_MEMORY;
memcpy(fInfos, infos, sizeof(Port::Info) * count);
fCount = count;
return B_OK;
}
status_t SetTo(const BMessage* message)
{
Unset();
if (!message)
return B_BAD_VALUE;
const void* infos;
ssize_t size;
const char* fsName;
if (message->FindData("infos", B_RAW_TYPE, &infos, &size) != B_OK
|| size < 0 || message->FindString("fsName", &fsName) != B_OK) {
return B_BAD_VALUE;
}
return SetTo(fsName, (const Port::Info*)infos,
size / sizeof(Port::Info));
}
void Unset()
{
fName.Unset();
delete[] fInfos;
fInfos = NULL;
fCount = 0;
}
const char* GetName() const
{
return fName.GetString();
}
Port::Info* GetInfos() const
{
return fInfos;
}
int32 CountInfos() const
{
return fCount;
}
int32 GetSize() const
{
return fCount * sizeof(Port::Info);
}
status_t Archive(BMessage* archive)
{
if (!fName.GetString() || !fInfos)
return B_NO_INIT;
status_t error = archive->AddString("fsName", fName.GetString());
if (error != B_OK)
return error;
return archive->AddData("infos", B_RAW_TYPE, fInfos,
fCount * sizeof(Port::Info));
}
private:
String fName;
Port::Info* fInfos;
int32 fCount;
};
} // namespace UserlandFS
using UserlandFS::FSInfo;
#endif // USERLAND_FS_FS_INFO_H
@@ -0,0 +1,145 @@
// FileSystem.cpp
#include <Application.h>
#include <Autolock.h>
#include <Entry.h>
#include <Message.h>
#include <Messenger.h>
#include <Roster.h>
#include "Debug.h"
#include "DispatcherDefs.h"
#include "FileSystem.h"
#include "ServerDefs.h"
// constructor
FileSystem::FileSystem(const char* name, status_t* _error)
: LazyInitializable(),
Referencable(),
fName(),
fInfo(NULL),
fTeam(-1),
fFinishInitSemaphore(-1),
fTeamLock()
{
status_t error = B_OK;
if (!fName.SetTo(name))
error = B_NO_MEMORY;
if (_error)
*_error = error;
}
// constructor
FileSystem::FileSystem(team_id team, FSInfo* info, status_t* _error)
: LazyInitializable(false),
Referencable(),
fName(),
fInfo(info),
fTeam(team),
fFinishInitSemaphore(-1),
fTeamLock()
{
status_t error = B_OK;
if (!fName.SetTo(info->GetName()))
error = B_NO_MEMORY;
if (_error)
*_error = error;
}
// destructor
FileSystem::~FileSystem()
{
if (fFinishInitSemaphore >= 0)
delete_sem(fFinishInitSemaphore);
delete fInfo;
}
// GetName
const char*
FileSystem::GetName() const
{
return fName.GetString();
}
// GetInfo
const FSInfo*
FileSystem::GetInfo() const
{
return fInfo;
}
// GetTeam
team_id
FileSystem::GetTeam() const
{
BAutolock _(fTeamLock);
return fTeam;
}
// CompleteInit
void
FileSystem::CompleteInit(FSInfo* info)
{
fInfo = info;
if (fFinishInitSemaphore >= 0)
release_sem(fFinishInitSemaphore);
}
// AbortInit
void
FileSystem::AbortInit()
{
if (fInitStatus == B_OK)
fInitStatus = B_NO_INIT;
if (fFinishInitSemaphore >= 0)
release_sem(fFinishInitSemaphore);
}
// FirstTimeInit
status_t
FileSystem::FirstTimeInit()
{
if (fName.GetLength() == 0)
RETURN_ERROR(B_BAD_VALUE);
// create the init finish semaphore
fFinishInitSemaphore = create_sem(0, "FS init finish sem");
if (fFinishInitSemaphore < 0)
return fFinishInitSemaphore;
// get a server entry ref
app_info appInfo;
status_t error = be_app->GetAppInfo(&appInfo);
if (error != B_OK)
RETURN_ERROR(error);
// launch a server instance
team_id team = -1;
fTeamLock.Lock();
if (gServerSettings.ShallEnterDebugger()) {
int argc = 2;
const char *argv[] = { "--debug", fName.GetString(), NULL };
error = be_roster->Launch(&appInfo.ref, argc, argv, &team);
} else {
int argc = 1;
const char *argv[] = { fName.GetString(), NULL };
error = be_roster->Launch(&appInfo.ref, argc, argv, &team);
}
fTeam = team;
fTeamLock.Unlock();
if (error != B_OK)
RETURN_ERROR(error);
// wait for the initialization to complete/fail
error = _WaitForInitToFinish();
RETURN_ERROR(error);
}
// _WaitForInitToFinish
status_t
FileSystem::_WaitForInitToFinish()
{
status_t error = acquire_sem(fFinishInitSemaphore);
delete_sem(fFinishInitSemaphore);
fFinishInitSemaphore = -1;
if (error != B_OK)
return error;
return (fInfo ? B_OK : B_ERROR);
}
@@ -0,0 +1,46 @@
// FileSystem.h
#ifndef USERLAND_FS_FILE_SYSTEM_H
#define USERLAND_FS_FILE_SYSTEM_H
#include <Locker.h>
#include "FSInfo.h"
#include "LazyInitializable.h"
#include "Referencable.h"
#include "String.h"
namespace UserlandFS {
class FileSystem : public LazyInitializable, public Referencable {
public:
FileSystem(const char* name, status_t* error);
FileSystem(team_id team, FSInfo* info,
status_t* error);
~FileSystem();
const char* GetName() const;
const FSInfo* GetInfo() const;
team_id GetTeam() const;
void CompleteInit(FSInfo* info);
void AbortInit();
private:
virtual status_t FirstTimeInit();
status_t _WaitForInitToFinish();
private:
String fName;
FSInfo* fInfo;
team_id fTeam;
sem_id fFinishInitSemaphore;
mutable BLocker fTeamLock;
};
} // namespace UserlandFS
using UserlandFS::FileSystem;
#endif // USERLAND_FS_FILE_SYSTEM_H
@@ -0,0 +1,54 @@
SubDir HAIKU_TOP src tests add-ons kernel file_systems userlandfs r5 src
server ;
SetSubDirSupportedPlatforms r5 bone dano ;
local userlandFSTop = [ FDirName $(HAIKU_TOP) src tests add-ons kernel
file_systems userlandfs r5 ] ;
local userlandFSIncludes = [ FDirName $(userlandFSTop) headers ] ;
SubDirSysHdrs [ FDirName $(userlandFSIncludes) public ] ;
SubDirHdrs [ FDirName $(userlandFSIncludes) private ] ;
SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ;
SEARCH_SOURCE += [ FDirName $(userlandFSTop) src private ] ;
SEARCH_SOURCE += [ FDirName $(userlandFSTop) src shared ] ;
DEFINES += USER=1 ;
DEFINES += DEBUG_APP="\\\"UserlandFSServer\\\"" ;
Application <test>UserlandFSServer
: AreaSupport.cpp
Debug.cpp
DispatcherDefs.cpp
driver_settings.c
LazyInitializable.cpp
Locker.cpp
ObjectTracker.cpp
Port.cpp
Referencable.cpp
Request.cpp
RequestAllocator.cpp
RequestHandler.cpp
RequestPort.cpp
Requests.cpp
SingleReplyRequestHandler.cpp
String.cpp
cache.c
sysdep.c
FileSystem.cpp
kernel_emu.cpp
KernelUserFileSystem.cpp
KernelUserVolume.cpp
main.cpp
RequestThread.cpp
ServerDefs.cpp
UserFileSystem.cpp
UserlandFSDispatcher.cpp
UserlandFSServer.cpp
UserlandRequestHandler.cpp
UserVolume.cpp
: be
;
@@ -0,0 +1,45 @@
// KernelUserFileSystem.cpp
#include <new>
#include "KernelUserFileSystem.h"
#include "KernelUserVolume.h"
// constructor
KernelUserFileSystem::KernelUserFileSystem(vnode_ops* fsOps)
: UserFileSystem(),
fFSOps(fsOps)
{
}
// destructor
KernelUserFileSystem::~KernelUserFileSystem()
{
}
// CreateVolume
status_t
KernelUserFileSystem::CreateVolume(UserVolume** volume, nspace_id id)
{
// check initialization and parameters
if (!fFSOps)
return B_BAD_VALUE;
if (!volume)
return B_BAD_VALUE;
// create the volume
*volume = new(nothrow) KernelUserVolume(this, id, fFSOps);
if (!*volume)
return B_NO_MEMORY;
return B_OK;
}
// DeleteVolume
status_t
KernelUserFileSystem::DeleteVolume(UserVolume* volume)
{
if (!volume || !dynamic_cast<KernelUserVolume*>(volume))
return B_BAD_VALUE;
delete volume;
return B_OK;
}
@@ -0,0 +1,26 @@
// KernelUserFileSystem.h
#ifndef USERLAND_FS_KERNEL_USER_FILE_SYSTEM_H
#define USERLAND_FS_KERNEL_USER_FILE_SYSTEM_H
#include "UserFileSystem.h"
namespace UserlandFS {
class KernelUserFileSystem : public UserFileSystem {
public:
KernelUserFileSystem(vnode_ops* fsOps);
virtual ~KernelUserFileSystem();
virtual status_t CreateVolume(UserVolume** volume, nspace_id id);
virtual status_t DeleteVolume(UserVolume* volume);
private:
vnode_ops* fFSOps;
};
} // namespace UserlandFS
using UserlandFS::KernelUserFileSystem;
#endif // USERLAND_FS_KERNEL_USER_FILE_SYSTEM_H
@@ -0,0 +1,606 @@
// KernelUserVolume.cpp
#include "KernelUserVolume.h"
// constructor
KernelUserVolume::KernelUserVolume(UserFileSystem* fileSystem, nspace_id id,
vnode_ops* fsOps)
: UserVolume(fileSystem, id),
fFSOps(fsOps),
fVolumeCookie(NULL)
{
}
// destructor
KernelUserVolume::~KernelUserVolume()
{
}
// #pragma mark -
// #pragma mark ----- FS -----
// Mount
status_t
KernelUserVolume::Mount(const char* device, ulong flags, const char* parameters,
int32 len, vnode_id* rootID)
{
if (!fFSOps->mount)
return B_BAD_VALUE;
return fFSOps->mount(GetID(), device, flags, (void*)parameters, len,
&fVolumeCookie, rootID);
}
// Unmount
status_t
KernelUserVolume::Unmount()
{
if (!fFSOps->unmount)
return B_BAD_VALUE;
return fFSOps->unmount(fVolumeCookie);
}
// Sync
status_t
KernelUserVolume::Sync()
{
if (!fFSOps->sync)
return B_BAD_VALUE;
return fFSOps->sync(fVolumeCookie);
}
// ReadFSStat
status_t
KernelUserVolume::ReadFSStat(fs_info* info)
{
if (!fFSOps->rfsstat)
return B_BAD_VALUE;
return fFSOps->rfsstat(fVolumeCookie, info);
}
// WriteFSStat
status_t
KernelUserVolume::WriteFSStat(struct fs_info *info, long mask)
{
if (!fFSOps->wfsstat)
return B_BAD_VALUE;
return fFSOps->wfsstat(fVolumeCookie, info, mask);
}
// #pragma mark -
// #pragma mark ----- vnodes -----
// ReadVNode
status_t
KernelUserVolume::ReadVNode(vnode_id vnid, char reenter, void** node)
{
if (!fFSOps->read_vnode)
return B_BAD_VALUE;
return fFSOps->read_vnode(fVolumeCookie, vnid, reenter, node);
}
// WriteVNode
status_t
KernelUserVolume::WriteVNode(void* node, char reenter)
{
if (!fFSOps->write_vnode)
return B_BAD_VALUE;
return fFSOps->write_vnode(fVolumeCookie, node, reenter);
}
// RemoveVNode
status_t
KernelUserVolume::RemoveVNode(void* node, char reenter)
{
if (!fFSOps->remove_vnode)
return B_BAD_VALUE;
return fFSOps->remove_vnode(fVolumeCookie, node, reenter);
}
// #pragma mark -
// #pragma mark ----- nodes -----
// FSync
status_t
KernelUserVolume::FSync(void* node)
{
if (!fFSOps->fsync)
return B_BAD_VALUE;
return fFSOps->fsync(fVolumeCookie, node);
}
// ReadStat
status_t
KernelUserVolume::ReadStat(void* node, struct stat* st)
{
if (!fFSOps->rstat)
return B_BAD_VALUE;
return fFSOps->rstat(fVolumeCookie, node, st);
}
// WriteStat
status_t
KernelUserVolume::WriteStat(void* node, struct stat* st, long mask)
{
if (!fFSOps->wstat)
return B_BAD_VALUE;
return fFSOps->wstat(fVolumeCookie, node, st, mask);
}
// Access
status_t
KernelUserVolume::Access(void* node, int mode)
{
if (!fFSOps->access)
return B_BAD_VALUE;
return fFSOps->access(fVolumeCookie, node, mode);
}
// #pragma mark -
// #pragma mark ----- files -----
// Create
status_t
KernelUserVolume::Create(void* dir, const char* name, int openMode, int mode,
vnode_id* vnid, void** cookie)
{
if (!fFSOps->create)
return B_BAD_VALUE;
return fFSOps->create(fVolumeCookie, dir, name, openMode, mode, vnid,
cookie);
}
// Open
status_t
KernelUserVolume::Open(void* node, int openMode, void** cookie)
{
if (!fFSOps->open)
return B_BAD_VALUE;
return fFSOps->open(fVolumeCookie, node, openMode, cookie);
}
// Close
status_t
KernelUserVolume::Close(void* node, void* cookie)
{
if (!fFSOps->close)
return B_OK;
return fFSOps->close(fVolumeCookie, node, cookie);
}
// FreeCookie
status_t
KernelUserVolume::FreeCookie(void* node, void* cookie)
{
if (!fFSOps->free_cookie)
return B_OK;
return fFSOps->free_cookie(fVolumeCookie, node, cookie);
}
// Read
status_t
KernelUserVolume::Read(void* node, void* cookie, off_t pos, void* buffer,
size_t bufferSize, size_t* bytesRead)
{
if (!fFSOps->read)
return B_BAD_VALUE;
*bytesRead = bufferSize;
return fFSOps->read(fVolumeCookie, node, cookie, pos, buffer, bytesRead);
}
// Write
status_t
KernelUserVolume::Write(void* node, void* cookie, off_t pos, const void* buffer,
size_t bufferSize, size_t* bytesWritten)
{
if (!fFSOps->write)
return B_BAD_VALUE;
*bytesWritten = bufferSize;
return fFSOps->write(fVolumeCookie, node, cookie, pos, buffer,
bytesWritten);
}
// IOCtl
status_t
KernelUserVolume::IOCtl(void* node, void* cookie, int command, void *buffer,
size_t size)
{
if (!fFSOps->ioctl)
return B_BAD_VALUE;
return fFSOps->ioctl(fVolumeCookie, node, cookie, command, buffer, size);
}
// SetFlags
status_t
KernelUserVolume::SetFlags(void* node, void* cookie, int flags)
{
if (!fFSOps->setflags)
return B_BAD_VALUE;
return fFSOps->setflags(fVolumeCookie, node, cookie, flags);
}
// Select
status_t
KernelUserVolume::Select(void* node, void* cookie, uint8 event, uint32 ref,
selectsync* sync)
{
if (!fFSOps->select) {
notify_select_event(sync, ref);
return B_OK;
}
return fFSOps->select(fVolumeCookie, node, cookie, event, ref, sync);
}
// Deselect
status_t
KernelUserVolume::Deselect(void* node, void* cookie, uint8 event,
selectsync* sync)
{
if (!fFSOps->select || !fFSOps->deselect)
return B_OK;
return fFSOps->deselect(fVolumeCookie, node, cookie, event, sync);
}
// #pragma mark -
// #pragma mark ----- hard links / symlinks -----
// Link
status_t
KernelUserVolume::Link(void* dir, const char* name, void* node)
{
if (!fFSOps->link)
return B_BAD_VALUE;
return fFSOps->link(fVolumeCookie, dir, name, node);
}
// Unlink
status_t
KernelUserVolume::Unlink(void* dir, const char* name)
{
if (!fFSOps->unlink)
return B_BAD_VALUE;
return fFSOps->unlink(fVolumeCookie, dir, name);
}
// Symlink
status_t
KernelUserVolume::Symlink(void* dir, const char* name, const char* target)
{
if (!fFSOps->symlink)
return B_BAD_VALUE;
return fFSOps->symlink(fVolumeCookie, dir, name, target);
}
// ReadLink
status_t
KernelUserVolume::ReadLink(void* node, char* buffer, size_t bufferSize,
size_t* bytesRead)
{
if (!fFSOps->readlink)
return B_BAD_VALUE;
*bytesRead = bufferSize;
return fFSOps->readlink(fVolumeCookie, node, buffer, bytesRead);
}
// Rename
status_t
KernelUserVolume::Rename(void* oldDir, const char* oldName, void* newDir,
const char* newName)
{
if (!fFSOps->rename)
return B_BAD_VALUE;
return fFSOps->rename(fVolumeCookie, oldDir, oldName, newDir, newName);
}
// #pragma mark -
// #pragma mark ----- directories -----
// MkDir
status_t
KernelUserVolume::MkDir(void* dir, const char* name, int mode)
{
if (!fFSOps->mkdir)
return B_BAD_VALUE;
return fFSOps->mkdir(fVolumeCookie, dir, name, mode);
}
// RmDir
status_t
KernelUserVolume::RmDir(void* dir, const char* name)
{
if (!fFSOps->rmdir)
return B_BAD_VALUE;
return fFSOps->rmdir(fVolumeCookie, dir, name);
}
// OpenDir
status_t
KernelUserVolume::OpenDir(void* node, void** cookie)
{
if (!fFSOps->opendir)
return B_BAD_VALUE;
return fFSOps->opendir(fVolumeCookie, node, cookie);
}
// CloseDir
status_t
KernelUserVolume::CloseDir(void* node, void* cookie)
{
if (!fFSOps->closedir)
return B_OK;
return fFSOps->closedir(fVolumeCookie, node, cookie);
}
// FreeDirCookie
status_t
KernelUserVolume::FreeDirCookie(void* node, void* cookie)
{
if (!fFSOps->free_dircookie)
return B_OK;
return fFSOps->free_dircookie(fVolumeCookie, node, cookie);
}
// ReadDir
status_t
KernelUserVolume::ReadDir(void* node, void* cookie, void* buffer,
size_t bufferSize, int32 count, int32* countRead)
{
if (!fFSOps->readdir)
return B_BAD_VALUE;
*countRead = count;
return fFSOps->readdir(fVolumeCookie, node, cookie, countRead,
(dirent*)buffer, bufferSize);
}
// RewindDir
status_t
KernelUserVolume::RewindDir(void* node, void* cookie)
{
if (!fFSOps->rewinddir)
return B_BAD_VALUE;
return fFSOps->rewinddir(fVolumeCookie, node, cookie);
}
// Walk
status_t
KernelUserVolume::Walk(void* dir, const char* entryName, char** resolvedPath,
vnode_id* vnid)
{
if (!fFSOps->walk)
return B_BAD_VALUE;
return fFSOps->walk(fVolumeCookie, dir, entryName, resolvedPath, vnid);
}
// #pragma mark -
// #pragma mark ----- attributes -----
// OpenAttrDir
status_t
KernelUserVolume::OpenAttrDir(void* node, void** cookie)
{
if (!fFSOps->open_attrdir)
return B_BAD_VALUE;
return fFSOps->open_attrdir(fVolumeCookie, node, cookie);
}
// CloseAttrDir
status_t
KernelUserVolume::CloseAttrDir(void* node, void* cookie)
{
if (!fFSOps->close_attrdir)
return B_OK;
return fFSOps->close_attrdir(fVolumeCookie, node, cookie);
}
// FreeAttrDirCookie
status_t
KernelUserVolume::FreeAttrDirCookie(void* node, void* cookie)
{
if (!fFSOps->free_attrdircookie)
return B_OK;
return fFSOps->free_attrdircookie(fVolumeCookie, node, cookie);
}
// ReadAttrDir
status_t
KernelUserVolume::ReadAttrDir(void* node, void* cookie, void* buffer,
size_t bufferSize, int32 count, int32* countRead)
{
if (!fFSOps->read_attrdir)
return B_BAD_VALUE;
*countRead = count;
return fFSOps->read_attrdir(fVolumeCookie, node, cookie, countRead,
(struct dirent*)buffer, bufferSize);
}
// RewindAttrDir
status_t
KernelUserVolume::RewindAttrDir(void* node, void* cookie)
{
if (!fFSOps->rewind_attrdir)
return B_BAD_VALUE;
return fFSOps->rewind_attrdir(fVolumeCookie, node, cookie);
}
// ReadAttr
status_t
KernelUserVolume::ReadAttr(void* node, const char* name, int type, off_t pos,
void* buffer, size_t bufferSize, size_t* bytesRead)
{
if (!fFSOps->read_attr)
return B_BAD_VALUE;
*bytesRead = bufferSize;
return fFSOps->read_attr(fVolumeCookie, node, name, type, buffer, bytesRead,
pos);
}
// WriteAttr
status_t
KernelUserVolume::WriteAttr(void* node, const char* name, int type, off_t pos,
const void* buffer, size_t bufferSize, size_t* bytesWritten)
{
if (!fFSOps->write_attr)
return B_BAD_VALUE;
*bytesWritten = bufferSize;
return fFSOps->write_attr(fVolumeCookie, node, name, type, buffer,
bytesWritten, pos);
}
// RemoveAttr
status_t
KernelUserVolume::RemoveAttr(void* node, const char* name)
{
if (!fFSOps->remove_attr)
return B_BAD_VALUE;
return fFSOps->remove_attr(fVolumeCookie, node, name);
}
// RenameAttr
status_t
KernelUserVolume::RenameAttr(void* node, const char* oldName, const char* newName)
{
if (!fFSOps->rename_attr)
return B_BAD_VALUE;
return fFSOps->rename_attr(fVolumeCookie, node, oldName, newName);
}
// StatAttr
status_t
KernelUserVolume::StatAttr(void* node, const char* name,
struct attr_info* attrInfo)
{
if (!fFSOps->stat_attr)
return B_BAD_VALUE;
return fFSOps->stat_attr(fVolumeCookie, node, name, attrInfo);
}
// #pragma mark -
// #pragma mark ----- indices -----
// OpenIndexDir
status_t
KernelUserVolume::OpenIndexDir(void** cookie)
{
if (!fFSOps->open_indexdir)
return B_BAD_VALUE;
return fFSOps->open_indexdir(fVolumeCookie, cookie);
}
// CloseIndexDir
status_t
KernelUserVolume::CloseIndexDir(void* cookie)
{
if (!fFSOps->close_indexdir)
return B_OK;
return fFSOps->close_indexdir(fVolumeCookie, cookie);
}
// FreeIndexDirCookie
status_t
KernelUserVolume::FreeIndexDirCookie(void* cookie)
{
if (!fFSOps->free_indexdircookie)
return B_OK;
return fFSOps->free_indexdircookie(fVolumeCookie, NULL, cookie);
}
// ReadIndexDir
status_t
KernelUserVolume::ReadIndexDir(void* cookie, void* buffer, size_t bufferSize,
int32 count, int32* countRead)
{
if (!fFSOps->read_indexdir)
return B_BAD_VALUE;
*countRead = count;
return fFSOps->read_indexdir(fVolumeCookie, cookie, countRead,
(struct dirent*)buffer, bufferSize);
}
// RewindIndexDir
status_t
KernelUserVolume::RewindIndexDir(void* cookie)
{
if (!fFSOps->rewind_indexdir)
return B_BAD_VALUE;
return fFSOps->rewind_indexdir(fVolumeCookie, cookie);
}
// CreateIndex
status_t
KernelUserVolume::CreateIndex(const char* name, int type, int flags)
{
if (!fFSOps->create_index)
return B_BAD_VALUE;
return fFSOps->create_index(fVolumeCookie, name, type, flags);
}
// RemoveIndex
status_t
KernelUserVolume::RemoveIndex(const char* name)
{
if (!fFSOps->remove_index)
return B_BAD_VALUE;
return fFSOps->remove_index(fVolumeCookie, name);
}
// RenameIndex
status_t
KernelUserVolume::RenameIndex(const char* oldName, const char* newName)
{
if (!fFSOps->rename_index)
return B_BAD_VALUE;
return fFSOps->rename_index(fVolumeCookie, oldName, newName);
}
// StatIndex
status_t
KernelUserVolume::StatIndex(const char *name, struct index_info* indexInfo)
{
if (!fFSOps->stat_index)
return B_BAD_VALUE;
return fFSOps->stat_index(fVolumeCookie, name, indexInfo);
}
// #pragma mark -
// #pragma mark ----- queries -----
// OpenQuery
status_t
KernelUserVolume::OpenQuery(const char* queryString, ulong flags, port_id port,
long token, void** cookie)
{
if (!fFSOps->open_query)
return B_BAD_VALUE;
return fFSOps->open_query(fVolumeCookie, queryString, flags, port,
token, cookie);
}
// CloseQuery
status_t
KernelUserVolume::CloseQuery(void* cookie)
{
if (!fFSOps->close_query)
return B_OK;
return fFSOps->close_query(fVolumeCookie, cookie);
}
// FreeQueryCookie
status_t
KernelUserVolume::FreeQueryCookie(void* cookie)
{
if (!fFSOps->free_querycookie)
return B_OK;
return fFSOps->free_querycookie(fVolumeCookie, NULL, cookie);
}
// ReadQuery
status_t
KernelUserVolume::ReadQuery(void* cookie, void* buffer, size_t bufferSize,
int32 count, int32* countRead)
{
if (!fFSOps->read_query)
return B_BAD_VALUE;
*countRead = count;
return fFSOps->read_query(fVolumeCookie, cookie, countRead,
(struct dirent*)buffer, bufferSize);
}
@@ -0,0 +1,139 @@
// KernelUserVolume.h
#ifndef USERLAND_FS_KERNEL_FS_VOLUME_H
#define USERLAND_FS_KERNEL_FS_VOLUME_H
#include "UserVolume.h"
struct vnode_ops;
namespace UserlandFS {
class KernelUserVolume : public UserVolume {
public:
KernelUserVolume(UserFileSystem* fileSystem,
nspace_id id, vnode_ops* fsOps);
virtual ~KernelUserVolume();
// FS
virtual status_t Mount(const char* device, ulong flags,
const char* parameters, int32 len,
vnode_id* rootID);
virtual status_t Unmount();
virtual status_t Sync();
virtual status_t ReadFSStat(fs_info* info);
virtual status_t WriteFSStat(struct fs_info *info, long mask);
// vnodes
virtual status_t ReadVNode(vnode_id vnid, char reenter,
void** node);
virtual status_t WriteVNode(void* node, char reenter);
virtual status_t RemoveVNode(void* node, char reenter);
// nodes
virtual status_t FSync(void* node);
virtual status_t ReadStat(void* node, struct stat* st);
virtual status_t WriteStat(void* node, struct stat* st,
long mask);
virtual status_t Access(void* node, int mode);
// files
virtual status_t Create(void* dir, const char* name,
int openMode, int mode, vnode_id* vnid,
void** cookie);
virtual status_t Open(void* node, int openMode, void** cookie);
virtual status_t Close(void* node, void* cookie);
virtual status_t FreeCookie(void* node, void* cookie);
virtual status_t Read(void* node, void* cookie, off_t pos,
void* buffer, size_t bufferSize,
size_t* bytesRead);
virtual status_t Write(void* node, void* cookie, off_t pos,
const void* buffer, size_t bufferSize,
size_t* bytesWritten);
virtual status_t IOCtl(void* node, void* cookie, int command,
void *buffer, size_t size);
virtual status_t SetFlags(void* node, void* cookie, int flags);
virtual status_t Select(void* node, void* cookie, uint8 event,
uint32 ref, selectsync* sync);
virtual status_t Deselect(void* node, void* cookie, uint8 event,
selectsync* sync);
// hard links / symlinks
virtual status_t Link(void* dir, const char* name, void* node);
virtual status_t Unlink(void* dir, const char* name);
virtual status_t Symlink(void* dir, const char* name,
const char* target);
virtual status_t ReadLink(void* node, char* buffer,
size_t bufferSize, size_t* bytesRead);
virtual status_t Rename(void* oldDir, const char* oldName,
void* newDir, const char* newName);
// directories
virtual status_t MkDir(void* dir, const char* name, int mode);
virtual status_t RmDir(void* dir, const char* name);
virtual status_t OpenDir(void* node, void** cookie);
virtual status_t CloseDir(void* node, void* cookie);
virtual status_t FreeDirCookie(void* node, void* cookie);
virtual status_t ReadDir(void* node, void* cookie,
void* buffer, size_t bufferSize,
int32 count, int32* countRead);
virtual status_t RewindDir(void* node, void* cookie);
virtual status_t Walk(void* dir, const char* entryName,
char** resolvedPath, vnode_id* vnid);
// attributes
virtual status_t OpenAttrDir(void* node, void** cookie);
virtual status_t CloseAttrDir(void* node, void* cookie);
virtual status_t FreeAttrDirCookie(void* node, void* cookie);
virtual status_t ReadAttrDir(void* node, void* cookie,
void* buffer, size_t bufferSize,
int32 count, int32* countRead);
virtual status_t RewindAttrDir(void* node, void* cookie);
virtual status_t ReadAttr(void* node, const char* name,
int type, off_t pos, void* buffer,
size_t bufferSize, size_t* bytesRead);
virtual status_t WriteAttr(void* node, const char* name,
int type, off_t pos, const void* buffer,
size_t bufferSize, size_t* bytesWritten);
virtual status_t RemoveAttr(void* node, const char* name);
virtual status_t RenameAttr(void* node, const char* oldName,
const char* newName);
virtual status_t StatAttr(void* node, const char* name,
struct attr_info* attrInfo);
// indices
virtual status_t OpenIndexDir(void** cookie);
virtual status_t CloseIndexDir(void* cookie);
virtual status_t FreeIndexDirCookie(void* cookie);
virtual status_t ReadIndexDir(void* cookie, void* buffer,
size_t bufferSize, int32 count,
int32* countRead);
virtual status_t RewindIndexDir(void* cookie);
virtual status_t CreateIndex(const char* name, int type,
int flags);
virtual status_t RemoveIndex(const char* name);
virtual status_t RenameIndex(const char* oldName,
const char* newName);
virtual status_t StatIndex(const char *name,
struct index_info* indexInfo);
// queries
virtual status_t OpenQuery(const char* queryString,
ulong flags, port_id port, long token,
void** cookie);
virtual status_t CloseQuery(void* cookie);
virtual status_t FreeQueryCookie(void* cookie);
virtual status_t ReadQuery(void* cookie, void* buffer,
size_t bufferSize, int32 count,
int32* countRead);
private:
vnode_ops* fFSOps;
void* fVolumeCookie;
};
} // namespace UserlandFS
using UserlandFS::KernelUserVolume;
#endif // USERLAND_FS_KERNEL_FS_VOLUME_H
@@ -0,0 +1,179 @@
// RequestThread.cpp
#include <new>
#include <TLS.h>
#include "RequestThread.h"
#include "ServerDefs.h"
#include "UserlandRequestHandler.h"
static const int32 sTLSVariable = tls_allocate();
// constructor
RequestThreadContext::RequestThreadContext(UserVolume* volume)
: fPreviousContext(NULL),
fThread(NULL),
fVolume(volume)
{
fThread = RequestThread::GetCurrentThread();
if (fThread) {
fPreviousContext = fThread->GetContext();
fThread->SetContext(this);
}
}
// destructor
RequestThreadContext::~RequestThreadContext()
{
if (fThread)
fThread->SetContext(fPreviousContext);
}
// GetThread
RequestThread*
RequestThreadContext::GetThread() const
{
return fThread;
}
// GetVolume
UserlandFS::UserVolume*
RequestThreadContext::GetVolume() const
{
return fVolume;
}
// RequestThread
// constructor
RequestThread::RequestThread()
: fThread(-1),
fFileSystem(NULL),
fPort(NULL),
fContext(NULL),
fTerminating(false)
{
}
// destructor
RequestThread::~RequestThread()
{
PrepareTermination();
Terminate();
delete fPort;
}
// Init
status_t
RequestThread::Init(UserFileSystem* fileSystem)
{
if (!fileSystem)
return B_BAD_VALUE;
// create the port
fPort = new(nothrow) RequestPort(kRequestPortSize);
if (!fPort)
return B_NO_MEMORY;
status_t error = fPort->InitCheck();
if (error != B_OK)
return error;
// spawn the thread
fThread = spawn_thread(_ThreadEntry, "request thread", B_NORMAL_PRIORITY,
this);
if (fThread < 0)
return fThread;
fFileSystem = fileSystem;
return B_OK;
}
// Run
void
RequestThread::Run()
{
resume_thread(fThread);
}
// PrepareTermination
void
RequestThread::PrepareTermination()
{
if (fTerminating)
return;
fTerminating = true;
if (fPort)
fPort->Close();
}
// Terminate
void
RequestThread::Terminate()
{
if (fThread >= 0) {
int32 result;
wait_for_thread(fThread, &result);
fThread = -1;
}
}
// GetPortInfo
const Port::Info*
RequestThread::GetPortInfo() const
{
return (fPort ? fPort->GetPortInfo() : NULL);
}
// GetFileSystem
UserlandFS::UserFileSystem*
RequestThread::GetFileSystem() const
{
return fFileSystem;
}
// GetPort
RequestPort*
RequestThread::GetPort() const
{
return fPort;
}
// GetContext
RequestThreadContext*
RequestThread::GetContext() const
{
return fContext;
}
// GetCurrentThread
RequestThread*
RequestThread::GetCurrentThread()
{
return (RequestThread*)tls_get(sTLSVariable);
}
// SetContext
void
RequestThread::SetContext(RequestThreadContext* context)
{
fContext = context;
}
// _ThreadEntry
int32
RequestThread::_ThreadEntry(void* data)
{
return ((RequestThread*)data)->_ThreadLoop();
}
// _ThreadLoop
int32
RequestThread::_ThreadLoop()
{
tls_set(sTLSVariable, this);
if (!fTerminating) {
UserlandRequestHandler handler(fFileSystem, false);
return fPort->HandleRequests(&handler);
}
return B_OK;
}
@@ -0,0 +1,69 @@
// RequestThread.h
#ifndef USERLAND_FS_REQUEST_THREAD_H
#define USERLAND_FS_REQUEST_THREAD_H
#include "RequestPort.h"
namespace UserlandFS {
class RequestThread;
class UserFileSystem;
class UserVolume;
// RequestThreadContext
class RequestThreadContext {
public:
RequestThreadContext(UserVolume* volume);
~RequestThreadContext();
RequestThread* GetThread() const;
UserVolume* GetVolume() const;
private:
RequestThreadContext* fPreviousContext;
RequestThread* fThread;
UserVolume* fVolume;
};
// RequestThread
class RequestThread {
public:
RequestThread();
~RequestThread();
status_t Init(UserFileSystem* fileSystem);
void Run();
void PrepareTermination();
void Terminate();
const Port::Info* GetPortInfo() const;
UserFileSystem* GetFileSystem() const;
RequestPort* GetPort() const;
RequestThreadContext* GetContext() const;
static RequestThread* GetCurrentThread();
private:
void SetContext(RequestThreadContext* context);
private:
static int32 _ThreadEntry(void* data);
int32 _ThreadLoop();
private:
friend class RequestThreadContext;
thread_id fThread;
UserFileSystem* fFileSystem;
RequestPort* fPort;
RequestThreadContext* fContext;
bool fTerminating;
};
} // namespace UserlandFS
using UserlandFS::RequestThreadContext;
using UserlandFS::RequestThread;
#endif // USERLAND_FS_REQUEST_THREAD_H
@@ -0,0 +1,34 @@
// ServerDefs.cpp
#include "ServerDefs.h"
// constructor
ServerSettings::ServerSettings()
: fEnterDebugger(false)
{
}
// destructor
ServerSettings::~ServerSettings()
{
}
// SetEnterDebugger
void
ServerSettings::SetEnterDebugger(bool enterDebugger)
{
fEnterDebugger = enterDebugger;
}
// ShallEnterDebugger
bool
ServerSettings::ShallEnterDebugger() const
{
return fEnterDebugger;
}
// the global settings
ServerSettings gServerSettings;
const char* kUserlandFSDispatcherClipboardName = "userland fs dispatcher";
@@ -0,0 +1,41 @@
// ServerDefs.h
#ifndef USERLAND_FS_SERVER_DEFS_H
#define USERLAND_FS_SERVER_DEFS_H
#include <OS.h>
namespace UserlandFS {
class ServerSettings {
public:
ServerSettings();
~ServerSettings();
void SetEnterDebugger(bool enterDebugger);
bool ShallEnterDebugger() const;
private:
bool fEnterDebugger;
};
extern ServerSettings gServerSettings;
enum {
UFS_REGISTER_FS = 'rgfs',
UFS_REGISTER_FS_ACK = 'rfsa',
UFS_REGISTER_FS_DENIED = 'rfsd',
};
extern const char* kUserlandFSDispatcherClipboardName;
static const int32 kRequestPortSize = B_PAGE_SIZE;
} // namespace UserlandFS
using UserlandFS::ServerSettings;
using UserlandFS::gServerSettings;
using UserlandFS::kUserlandFSDispatcherClipboardName;
using UserlandFS::kRequestPortSize;
#endif // USERLAND_FS_SERVER_DEFS_H
@@ -0,0 +1,14 @@
// UserFileSystem.cpp
#include "UserFileSystem.h"
// constructor
UserFileSystem::UserFileSystem()
{
}
// destructor
UserFileSystem::~UserFileSystem()
{
}
@@ -0,0 +1,27 @@
// UserFileSystem.h
#ifndef USERLAND_FS_USER_FILE_SYSTEM_H
#define USERLAND_FS_USER_FILE_SYSTEM_H
#include <fsproto.h>
#include <SupportDefs.h>
namespace UserlandFS {
class UserVolume;
class UserFileSystem {
public:
UserFileSystem();
virtual ~UserFileSystem();
virtual status_t CreateVolume(UserVolume** volume,
nspace_id id) = 0;
virtual status_t DeleteVolume(UserVolume* volume) = 0;
};
} // namespace UserlandFS
using UserlandFS::UserFileSystem;
#endif // USERLAND_FS_FILE_SYSTEM_H
@@ -0,0 +1,479 @@
// UserVolume.cpp
#include "UserVolume.h"
// constructor
UserVolume::UserVolume(UserFileSystem* fileSystem, nspace_id id)
: fFileSystem(fileSystem),
fID(id)
{
}
// destructor
UserVolume::~UserVolume()
{
}
// GetFileSystem
UserlandFS::UserFileSystem*
UserVolume::GetFileSystem() const
{
return fFileSystem;
}
// GetID
nspace_id
UserVolume::GetID() const
{
return fID;
}
// #pragma mark -
// #pragma mark ----- FS -----
// Mount
status_t
UserVolume::Mount(const char* device, ulong flags, const char* parameters,
int32 len, vnode_id* rootID)
{
return B_BAD_VALUE;
}
// Unmount
status_t
UserVolume::Unmount()
{
return B_BAD_VALUE;
}
// Sync
status_t
UserVolume::Sync()
{
return B_BAD_VALUE;
}
// ReadFSStat
status_t
UserVolume::ReadFSStat(fs_info* info)
{
return B_BAD_VALUE;
}
// WriteFSStat
status_t
UserVolume::WriteFSStat(struct fs_info *info, long mask)
{
return B_BAD_VALUE;
}
// #pragma mark -
// #pragma mark ----- vnodes -----
// ReadVNode
status_t
UserVolume::ReadVNode(vnode_id vnid, char reenter, void** node)
{
return B_BAD_VALUE;
}
// WriteVNode
status_t
UserVolume::WriteVNode(void* node, char reenter)
{
return B_BAD_VALUE;
}
// RemoveVNode
status_t
UserVolume::RemoveVNode(void* node, char reenter)
{
return B_BAD_VALUE;
}
// #pragma mark -
// #pragma mark ----- nodes -----
// FSync
status_t
UserVolume::FSync(void* node)
{
return B_BAD_VALUE;
}
// ReadStat
status_t
UserVolume::ReadStat(void* node, struct stat* st)
{
return B_BAD_VALUE;
}
// WriteStat
status_t
UserVolume::WriteStat(void* node, struct stat* st, long mask)
{
return B_BAD_VALUE;
}
// Access
status_t
UserVolume::Access(void* node, int mode)
{
return B_BAD_VALUE;
}
// #pragma mark -
// #pragma mark ----- files -----
// Create
status_t
UserVolume::Create(void* dir, const char* name, int openMode, int mode,
vnode_id* vnid, void** cookie)
{
return B_BAD_VALUE;
}
// Open
status_t
UserVolume::Open(void* node, int openMode, void** cookie)
{
return B_BAD_VALUE;
}
// Close
status_t
UserVolume::Close(void* node, void* cookie)
{
return B_BAD_VALUE;
}
// FreeCookie
status_t
UserVolume::FreeCookie(void* node, void* cookie)
{
return B_BAD_VALUE;
}
// Read
status_t
UserVolume::Read(void* node, void* cookie, off_t pos, void* buffer,
size_t bufferSize, size_t* bytesRead)
{
return B_BAD_VALUE;
}
// Write
status_t
UserVolume::Write(void* node, void* cookie, off_t pos, const void* buffer,
size_t bufferSize, size_t* bytesWritten)
{
return B_BAD_VALUE;
}
// IOCtl
status_t
UserVolume::IOCtl(void* node, void* cookie, int command, void *buffer,
size_t size)
{
return B_BAD_VALUE;
}
// SetFlags
status_t
UserVolume::SetFlags(void* node, void* cookie, int flags)
{
return B_BAD_VALUE;
}
// Select
status_t
UserVolume::Select(void* node, void* cookie, uint8 event, uint32 ref,
selectsync* sync)
{
return B_BAD_VALUE;
}
// Deselect
status_t
UserVolume::Deselect(void* node, void* cookie, uint8 event, selectsync* sync)
{
return B_BAD_VALUE;
}
// #pragma mark -
// #pragma mark ----- hard links / symlinks -----
// Link
status_t
UserVolume::Link(void* dir, const char* name, void* node)
{
return B_BAD_VALUE;
}
// Unlink
status_t
UserVolume::Unlink(void* dir, const char* name)
{
return B_BAD_VALUE;
}
// Symlink
status_t
UserVolume::Symlink(void* dir, const char* name, const char* target)
{
return B_BAD_VALUE;
}
// ReadLink
status_t
UserVolume::ReadLink(void* node, char* buffer, size_t bufferSize,
size_t* bytesRead)
{
return B_BAD_VALUE;
}
// Rename
status_t
UserVolume::Rename(void* oldDir, const char* oldName, void* newDir,
const char* newName)
{
return B_BAD_VALUE;
}
// #pragma mark -
// #pragma mark ----- directories -----
// MkDir
status_t
UserVolume::MkDir(void* dir, const char* name, int mode)
{
return B_BAD_VALUE;
}
// RmDir
status_t
UserVolume::RmDir(void* dir, const char* name)
{
return B_BAD_VALUE;
}
// OpenDir
status_t
UserVolume::OpenDir(void* node, void** cookie)
{
return B_BAD_VALUE;
}
// CloseDir
status_t
UserVolume::CloseDir(void* node, void* cookie)
{
return B_BAD_VALUE;
}
// FreeDirCookie
status_t
UserVolume::FreeDirCookie(void* node, void* cookie)
{
return B_BAD_VALUE;
}
// ReadDir
status_t
UserVolume::ReadDir(void* node, void* cookie, void* buffer, size_t bufferSize,
int32 count, int32* countRead)
{
return B_BAD_VALUE;
}
// RewindDir
status_t
UserVolume::RewindDir(void* node, void* cookie)
{
return B_BAD_VALUE;
}
// Walk
status_t
UserVolume::Walk(void* dir, const char* entryName, char** resolvedPath,
vnode_id* vnid)
{
return B_BAD_VALUE;
}
// #pragma mark -
// #pragma mark ----- attributes -----
// OpenAttrDir
status_t
UserVolume::OpenAttrDir(void* node, void** cookie)
{
return B_BAD_VALUE;
}
// CloseAttrDir
status_t
UserVolume::CloseAttrDir(void* node, void* cookie)
{
return B_BAD_VALUE;
}
// FreeAttrDirCookie
status_t
UserVolume::FreeAttrDirCookie(void* node, void* cookie)
{
return B_BAD_VALUE;
}
// ReadAttrDir
status_t
UserVolume::ReadAttrDir(void* node, void* cookie, void* buffer, size_t bufferSize,
int32 count, int32* countRead)
{
return B_BAD_VALUE;
}
// RewindAttrDir
status_t
UserVolume::RewindAttrDir(void* node, void* cookie)
{
return B_BAD_VALUE;
}
// ReadAttr
status_t
UserVolume::ReadAttr(void* node, const char* name, int type, off_t pos,
void* buffer, size_t bufferSize, size_t* bytesRead)
{
return B_BAD_VALUE;
}
// WriteAttr
status_t
UserVolume::WriteAttr(void* 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
UserVolume::RemoveAttr(void* node, const char* name)
{
return B_BAD_VALUE;
}
// RenameAttr
status_t
UserVolume::RenameAttr(void* node, const char* oldName, const char* newName)
{
return B_BAD_VALUE;
}
// StatAttr
status_t
UserVolume::StatAttr(void* node, const char* name, struct attr_info* attrInfo)
{
return B_BAD_VALUE;
}
// #pragma mark -
// #pragma mark ----- indices -----
// OpenIndexDir
status_t
UserVolume::OpenIndexDir(void** cookie)
{
return B_BAD_VALUE;
}
// CloseIndexDir
status_t
UserVolume::CloseIndexDir(void* cookie)
{
return B_BAD_VALUE;
}
// FreeIndexDirCookie
status_t
UserVolume::FreeIndexDirCookie(void* cookie)
{
return B_BAD_VALUE;
}
// ReadIndexDir
status_t
UserVolume::ReadIndexDir(void* cookie, void* buffer, size_t bufferSize,
int32 count, int32* countRead)
{
return B_BAD_VALUE;
}
// RewindIndexDir
status_t
UserVolume::RewindIndexDir(void* cookie)
{
return B_BAD_VALUE;
}
// CreateIndex
status_t
UserVolume::CreateIndex(const char* name, int type, int flags)
{
return B_BAD_VALUE;
}
// RemoveIndex
status_t
UserVolume::RemoveIndex(const char* name)
{
return B_BAD_VALUE;
}
// RenameIndex
status_t
UserVolume::RenameIndex(const char* oldName, const char* newName)
{
return B_BAD_VALUE;
}
// StatIndex
status_t
UserVolume::StatIndex(const char *name, struct index_info* indexInfo)
{
return B_BAD_VALUE;
}
// #pragma mark -
// #pragma mark ----- queries -----
// OpenQuery
status_t
UserVolume::OpenQuery(const char* queryString, ulong flags, port_id port,
long token, void** cookie)
{
return B_BAD_VALUE;
}
// CloseQuery
status_t
UserVolume::CloseQuery(void* cookie)
{
return B_BAD_VALUE;
}
// FreeQueryCookie
status_t
UserVolume::FreeQueryCookie(void* cookie)
{
return B_BAD_VALUE;
}
// ReadQuery
status_t
UserVolume::ReadQuery(void* cookie, void* buffer, size_t bufferSize, int32 count,
int32* countRead)
{
return B_BAD_VALUE;
}
@@ -0,0 +1,143 @@
// UserVolume.h
#ifndef USERLAND_FS_USER_VOLUME_H
#define USERLAND_FS_USER_VOLUME_H
#include <fsproto.h>
#include <SupportDefs.h>
namespace UserlandFS {
class UserFileSystem;
class UserVolume {
public:
UserVolume(UserFileSystem* fileSystem,
nspace_id id);
virtual ~UserVolume();
UserFileSystem* GetFileSystem() const;
nspace_id GetID() const;
// FS
virtual status_t Mount(const char* device, ulong flags,
const char* parameters, int32 len,
vnode_id* rootID);
virtual status_t Unmount();
virtual status_t Sync();
virtual status_t ReadFSStat(fs_info* info);
virtual status_t WriteFSStat(struct fs_info *info, long mask);
// vnodes
virtual status_t ReadVNode(vnode_id vnid, char reenter,
void** node);
virtual status_t WriteVNode(void* node, char reenter);
virtual status_t RemoveVNode(void* node, char reenter);
// nodes
virtual status_t FSync(void* node);
virtual status_t ReadStat(void* node, struct stat* st);
virtual status_t WriteStat(void* node, struct stat* st,
long mask);
virtual status_t Access(void* node, int mode);
// files
virtual status_t Create(void* dir, const char* name,
int openMode, int mode, vnode_id* vnid,
void** cookie);
virtual status_t Open(void* node, int openMode, void** cookie);
virtual status_t Close(void* node, void* cookie);
virtual status_t FreeCookie(void* node, void* cookie);
virtual status_t Read(void* node, void* cookie, off_t pos,
void* buffer, size_t bufferSize,
size_t* bytesRead);
virtual status_t Write(void* node, void* cookie, off_t pos,
const void* buffer, size_t bufferSize,
size_t* bytesWritten);
virtual status_t IOCtl(void* node, void* cookie, int command,
void *buffer, size_t size);
virtual status_t SetFlags(void* node, void* cookie, int flags);
virtual status_t Select(void* node, void* cookie, uint8 event,
uint32 ref, selectsync* sync);
virtual status_t Deselect(void* node, void* cookie, uint8 event,
selectsync* sync);
// hard links / symlinks
virtual status_t Link(void* dir, const char* name, void* node);
virtual status_t Unlink(void* dir, const char* name);
virtual status_t Symlink(void* dir, const char* name,
const char* target);
virtual status_t ReadLink(void* node, char* buffer,
size_t bufferSize, size_t* bytesRead);
virtual status_t Rename(void* oldDir, const char* oldName,
void* newDir, const char* newName);
// directories
virtual status_t MkDir(void* dir, const char* name, int mode);
virtual status_t RmDir(void* dir, const char* name);
virtual status_t OpenDir(void* node, void** cookie);
virtual status_t CloseDir(void* node, void* cookie);
virtual status_t FreeDirCookie(void* node, void* cookie);
virtual status_t ReadDir(void* node, void* cookie,
void* buffer, size_t bufferSize,
int32 count, int32* countRead);
virtual status_t RewindDir(void* node, void* cookie);
virtual status_t Walk(void* dir, const char* entryName,
char** resolvedPath, vnode_id* vnid);
// attributes
virtual status_t OpenAttrDir(void* node, void** cookie);
virtual status_t CloseAttrDir(void* node, void* cookie);
virtual status_t FreeAttrDirCookie(void* node, void* cookie);
virtual status_t ReadAttrDir(void* node, void* cookie,
void* buffer, size_t bufferSize,
int32 count, int32* countRead);
virtual status_t RewindAttrDir(void* node, void* cookie);
virtual status_t ReadAttr(void* node, const char* name,
int type, off_t pos, void* buffer,
size_t bufferSize, size_t* bytesRead);
virtual status_t WriteAttr(void* node, const char* name,
int type, off_t pos, const void* buffer,
size_t bufferSize, size_t* bytesWritten);
virtual status_t RemoveAttr(void* node, const char* name);
virtual status_t RenameAttr(void* node, const char* oldName,
const char* newName);
virtual status_t StatAttr(void* node, const char* name,
struct attr_info* attrInfo);
// indices
virtual status_t OpenIndexDir(void** cookie);
virtual status_t CloseIndexDir(void* cookie);
virtual status_t FreeIndexDirCookie(void* cookie);
virtual status_t ReadIndexDir(void* cookie, void* buffer,
size_t bufferSize, int32 count,
int32* countRead);
virtual status_t RewindIndexDir(void* cookie);
virtual status_t CreateIndex(const char* name, int type,
int flags);
virtual status_t RemoveIndex(const char* name);
virtual status_t RenameIndex(const char* oldName,
const char* newName);
virtual status_t StatIndex(const char *name,
struct index_info* indexInfo);
// queries
virtual status_t OpenQuery(const char* queryString,
ulong flags, port_id port, long token,
void** cookie);
virtual status_t CloseQuery(void* cookie);
virtual status_t FreeQueryCookie(void* cookie);
virtual status_t ReadQuery(void* cookie, void* buffer,
size_t bufferSize, int32 count,
int32* countRead);
protected:
UserFileSystem* fFileSystem;
nspace_id fID;
};
} // namespace UserlandFS
using UserlandFS::UserVolume;
#endif // USERLAND_FS_USER_VOLUME_H
@@ -0,0 +1,416 @@
// UserlandFSDispatcher.cpp
#include <new>
#include <Application.h>
#include <Clipboard.h>
#include <Locker.h>
#include <Message.h>
#include <Roster.h>
#include "AutoDeleter.h"
#include "AutoLocker.h"
#include "Compatibility.h"
#include "Debug.h"
#include "DispatcherDefs.h"
#include "FileSystem.h"
#include "FSInfo.h"
#include "RequestAllocator.h"
#include "RequestPort.h"
#include "Requests.h"
#include "ServerDefs.h"
#include "String.h"
#include "UserlandFSDispatcher.h"
// constructor
UserlandFSDispatcher::UserlandFSDispatcher(const char* signature)
: BApplication(signature),
fTerminating(false),
fRequestProcessor(-1),
fConnectionPort(-1),
fConnectionReplyPort(-1),
fRequestLock(),
fRequestPort(NULL)
{
}
// destructor
UserlandFSDispatcher::~UserlandFSDispatcher()
{
fTerminating = true;
// stop roster watching
be_roster->StopWatching(this);
// close/delete the ports
fRequestLock.Lock();
if (fRequestPort)
fRequestPort->Close();
fRequestLock.Unlock();
if (fConnectionPort >= 0)
delete_port(fConnectionPort);
if (fConnectionReplyPort >= 0)
delete_port(fConnectionReplyPort);
// wait for the request processor
if (fRequestProcessor >= 0) {
int32 result;
wait_for_thread(fRequestProcessor, &result);
}
}
// Init
status_t
UserlandFSDispatcher::Init()
{
// ensure that we are the only dispatcher
BClipboard clipboard(kUserlandFSDispatcherClipboardName);
if (!clipboard.Lock()) {
ERROR(("Failed to lock the clipboard.\n"));
return B_ERROR;
}
status_t error = B_OK;
if (BMessage* data = clipboard.Data()) {
// check the old value in the clipboard
BMessenger messenger;
if (data->FindMessenger("messenger", &messenger) == B_OK) {
if (messenger.IsValid()) {
PRINT(("There's already a dispatcher running.\n"));
error = B_ERROR;
}
}
// clear the clipboard
if (error == B_OK) {
clipboard.Clear();
data = clipboard.Data();
if (!data)
error = B_ERROR;
}
// add our messenger
if (error == B_OK) {
SET_ERROR(error, data->AddMessenger("messenger", be_app_messenger));
if (error == B_OK)
SET_ERROR(error, clipboard.Commit());
// work-around for BeOS R5: The very first commit to a clipboard
// (i.e. the one that creates the clipboard) seems to be ignored.
if (error == B_OK)
SET_ERROR(error, clipboard.Commit());
if (error != B_OK)
ERROR(("Failed to set clipboard messenger.\n"));
}
} else {
ERROR(("Failed to get clipboard data container\n"));
error = B_ERROR;
}
clipboard.Unlock();
if (error != B_OK)
return error;
// create the connection port and connection reply port
fConnectionPort = create_port(1, kUserlandFSDispatcherPortName);
if (fConnectionPort < 0)
return fConnectionPort;
fConnectionReplyPort = create_port(1, kUserlandFSDispatcherReplyPortName);
if (fConnectionReplyPort < 0)
return fConnectionReplyPort;
// start watching for terminated applications
error = be_roster->StartWatching(this, B_REQUEST_QUIT);
if (error != B_OK)
return error ;
// spawn request processor thread
fRequestProcessor = spawn_thread(_RequestProcessorEntry,
"main request processor", B_NORMAL_PRIORITY, this);
if (fRequestProcessor < 0)
return fRequestProcessor;
resume_thread(fRequestProcessor);
return B_OK;
}
// MessageReceived
void
UserlandFSDispatcher::MessageReceived(BMessage* message)
{
switch (message->what) {
case UFS_REGISTER_FS:
{
// get the team
team_id team;
status_t error = message->FindInt32("team", &team);
if (error != B_OK)
PRINT(("UFS_REGISTER_FS failed: no team\n"));
// get the FS info
FSInfo* info = NULL;
if (error == B_OK) {
info = new(nothrow) FSInfo;
if (info) {
error = info->SetTo(message);
} else {
error = B_NO_MEMORY;
PRINT(("UFS_REGISTER_FS failed: failed to allocate "
"FSInfo\n"));
}
}
ObjectDeleter<FSInfo> infoDeleter(info);
// find the FileSystem
FileSystem* fileSystem = NULL;
if (error == B_OK) {
AutoLocker<FileSystemMap> _(fFileSystems);
fileSystem = _GetFileSystemNoInit(team);
if (fileSystem) {
fileSystem->CompleteInit(info);
infoDeleter.Detach();
} else {
PRINT(("UFS_REGISTER_FS: no FileSystem found for "
"team %ld, trying to register anyway\n", team));
// try to find by name
fileSystem = fFileSystems.Get(info->GetName());
if (fileSystem) {
// there's already an FS with that name registered
PRINT(("UFS_REGISTER_FS failed: FileSystem with "
"name %s does already exist.\n", info->GetName()));
fileSystem = NULL;
error = B_ERROR;
} else {
// the FS is not known yet: create one
fileSystem = new FileSystem(team, info, &error);
if (fileSystem) {
infoDeleter.Detach();
} else {
error = B_NO_MEMORY;
PRINT(("UFS_REGISTER_FS failed: failed to allocate "
"FileSystem\n"));
}
// add it
if (error == B_OK) {
error = fFileSystems.Put(info->GetName(),
fileSystem);
if (error != B_OK) {
PRINT(("UFS_REGISTER_FS failed: failed to "
"add FileSystem\n"));
delete fileSystem;
}
}
}
}
}
// send the reply
if (error == B_OK)
message->SendReply(UFS_REGISTER_FS_ACK);
else
message->SendReply(UFS_REGISTER_FS_DENIED);
if (fileSystem)
_PutFileSystem(fileSystem);
break;
}
case B_SOME_APP_QUIT:
{
// get the team
team_id team;
status_t error = message->FindInt32("be:team", &team);
if (error != B_OK)
return;
// find the FileSystem
FileSystem* fileSystem = _GetFileSystemNoInit(team);
if (!fileSystem)
return;
// abort the initialization
fileSystem->AbortInit();
_PutFileSystem(fileSystem);
}
default:
BApplication::MessageReceived(message);
}
}
// _GetFileSystem
status_t
UserlandFSDispatcher::_GetFileSystem(const char* name, FileSystem** _fileSystem)
{
if (!name || !_fileSystem)
RETURN_ERROR(B_BAD_VALUE);
// get the file system
FileSystem* fileSystem;
{
AutoLocker<FileSystemMap> _(fFileSystems);
fileSystem = fFileSystems.Get(name);
if (fileSystem) {
fileSystem->AddReference();
} else {
// doesn't exists yet: create
status_t error;
fileSystem = new(nothrow) FileSystem(name, &error);
if (!fileSystem)
RETURN_ERROR(B_NO_MEMORY);
if (error == B_OK)
error = fFileSystems.Put(fileSystem->GetName(), fileSystem);
if (error != B_OK) {
delete fileSystem;
RETURN_ERROR(error);
}
}
}
// prepare access
status_t error = fileSystem->Access();
if (error != B_OK) {
_PutFileSystem(fileSystem);
RETURN_ERROR(error);
}
*_fileSystem = fileSystem;
return B_OK;
}
// _GetFileSystemNoInit
FileSystem*
UserlandFSDispatcher::_GetFileSystemNoInit(team_id team)
{
AutoLocker<FileSystemMap> _(fFileSystems);
for (FileSystemMap::Iterator it = fFileSystems.GetIterator();
it.HasNext();) {
FileSystem* fileSystem = it.Next().value;
if (fileSystem->GetTeam() == team) {
// found it
if (fileSystem)
fileSystem->AddReference();
return fileSystem;
}
}
return NULL;
}
// _PutFileSystem
status_t
UserlandFSDispatcher::_PutFileSystem(FileSystem* fileSystem)
{
if (!fileSystem)
RETURN_ERROR(B_BAD_VALUE);
AutoLocker<FileSystemMap> _(fFileSystems);
if (fFileSystems.Get(fileSystem->GetName()) != fileSystem)
RETURN_ERROR(B_BAD_VALUE);
if (fileSystem->RemoveReference() && fileSystem->InitCheck() != B_OK) {
PRINT(("removing FileSystem `%s'\n", fileSystem->GetName()));
fFileSystems.Remove(fileSystem->GetName());
delete fileSystem;
}
return B_OK;
}
// _WaitForConnection
bool
UserlandFSDispatcher::_WaitForConnection()
{
while (!fTerminating) {
int32 code;
char buffer;
size_t bytesRead = read_port(fConnectionPort, &code, &buffer, 0);
if (bytesRead >= 0 && code == UFS_DISPATCHER_CONNECT) {
const Port::Info* info = fRequestPort->GetPortInfo();
size_t bytesWritten = write_port(fConnectionReplyPort,
UFS_DISPATCHER_CONNECT_ACK, info, sizeof(Port::Info));
if (bytesWritten >= 0)
return true;
}
}
return false;
}
// _ProcessRequests
status_t
UserlandFSDispatcher::_ProcessRequests()
{
while (!fTerminating) {
Request* request;
status_t error = fRequestPort->ReceiveRequest(&request);
if (error != B_OK)
RETURN_ERROR(error);
RequestReleaser _(fRequestPort, request);
// check the request type
if (request->GetType() == UFS_DISCONNECT_REQUEST)
return B_OK;
if (request->GetType() != FS_CONNECT_REQUEST)
RETURN_ERROR(B_BAD_VALUE);
PRINT(("UserlandFSDispatcher::_ProcessRequests(): received FS connect "
"request\n"));
// it's an FS connect request
FSConnectRequest* connectRequest = (FSConnectRequest*)request;
// get the FS name
int32 len = connectRequest->fsName.GetSize();
status_t result = B_OK;
if (len <= 0)
result = B_BAD_DATA;
String fsName;
if (result == B_OK)
fsName.SetTo((const char*)connectRequest->fsName.GetData(), len);
if (result == B_OK && fsName.GetLength() == 0)
result = B_BAD_DATA;
// prepare the reply
RequestAllocator allocator(fRequestPort->GetPort());
FSConnectReply* reply;
error = AllocateRequest(allocator, &reply);
if (error != B_OK)
RETURN_ERROR(error);
FileSystem* fileSystem = NULL;
if (result == B_OK)
result = _GetFileSystem(fsName.GetString(), &fileSystem);
if (result == B_OK) {
const FSInfo* info = fileSystem->GetInfo();
result = allocator.AllocateData(reply->portInfos,
info->GetInfos(), info->GetSize(), sizeof(Port::Info));
if (result == B_OK)
reply->portInfoCount = info->CountInfos();
_PutFileSystem(fileSystem);
}
reply->error = result;
// send it
error = fRequestPort->SendRequest(&allocator);
if (error != B_OK)
RETURN_ERROR(error);
}
return B_OK;
}
// _RequestProcessorEntry
int32
UserlandFSDispatcher::_RequestProcessorEntry(void* data)
{
return ((UserlandFSDispatcher*)data)->_RequestProcessor();
}
// _RequestProcessor
int32
UserlandFSDispatcher::_RequestProcessor()
{
PRINT(("UserlandFSDispatcher::_RequestProcessor()\n"));
while (!fTerminating) {
// allocate a request port
status_t error = B_OK;
{
fRequestLock.Lock();
fRequestPort = new(nothrow) RequestPort(kRequestPortSize);
if (fRequestPort)
error = fRequestPort->InitCheck();
else
error = B_NO_MEMORY;
if (error != B_OK) {
delete fRequestPort;
fRequestPort = NULL;
}
fRequestLock.Unlock();
}
if (error != B_OK) {
be_app->PostMessage(B_QUIT_REQUESTED);
PRINT((" failed to allocate request port: %s\n", strerror(error)));
return error;
}
// wait for a connection and process the requests
if (_WaitForConnection()) {
PRINT(("UserlandFSDispatcher::_RequestProcessor(): connected\n"));
_ProcessRequests();
PRINT(("UserlandFSDispatcher::_RequestProcessor(): "
"disconnected\n"));
}
// delete the request port
fRequestLock.Lock();
delete fRequestPort;
fRequestPort = NULL;
fRequestLock.Unlock();
}
PRINT(("UserlandFSDispatcher::_RequestProcessor() done\n"));
return B_OK;
}
@@ -0,0 +1,65 @@
// UserlandFSDispatcher.h
#ifndef USERLAND_FS_DISPATCHER_H
#define USERLAND_FS_DISPATCHER_H
#include <Application.h>
#include <Locker.h>
#include <OS.h>
#include "HashMap.h"
namespace UserlandFSUtil {
class RequestPort;
class String;
}
using UserlandFSUtil::RequestPort;
using UserlandFSUtil::String;
namespace UserlandFS {
class FileSystem;
class UserlandFSDispatcher : public BApplication {
public:
UserlandFSDispatcher(const char* signature);
virtual ~UserlandFSDispatcher();
status_t Init();
virtual void MessageReceived(BMessage* message);
private:
status_t _GetFileSystem(const char* name,
FileSystem** fileSystem);
status_t _GetFileSystemNoInit(const char* name,
FileSystem** fileSystem);
FileSystem* _GetFileSystemNoInit(team_id team);
status_t _PutFileSystem(FileSystem* fileSystem);
bool _WaitForConnection();
status_t _ProcessRequests();
static int32 _RequestProcessorEntry(void* data);
int32 _RequestProcessor();
private:
typedef SynchronizedHashMap<String, FileSystem*> FileSystemMap;
bool fTerminating;
thread_id fRequestProcessor;
port_id fConnectionPort;
port_id fConnectionReplyPort;
BLocker fRequestLock;
RequestPort* fRequestPort;
FileSystemMap fFileSystems;
};
} // namespace UserlandFS
using UserlandFS::UserlandFSDispatcher;
#endif // USERLAND_FS_DISPATCHER_H
@@ -0,0 +1,197 @@
// UserlandFSServer.cpp
#include <new>
#include <stdio.h>
#include <string.h>
#include <Application.h>
#include <cache.h>
#include <Clipboard.h>
#include <FindDirectory.h>
#include <fsproto.h>
#include <image.h>
#include <Locker.h>
#include <Path.h>
#include "AutoLocker.h"
#include "Compatibility.h"
#include "Debug.h"
#include "DispatcherDefs.h"
#include "FSInfo.h"
#include "KernelUserFileSystem.h"
#include "RequestThread.h"
#include "ServerDefs.h"
#include "UserFileSystem.h"
#include "UserlandFSServer.h"
static const int32 kRequestThreadCount = 10;
static const int32 kMaxBlockCacheBlocks = 16384;
// constructor
UserlandFSServer::UserlandFSServer(const char* signature)
: BApplication(signature),
fAddOnImage(-1),
fFileSystem(NULL),
fNotificationRequestPort(NULL),
fRequestThreads(NULL),
fBlockCacheInitialized(false)
{
}
// destructor
UserlandFSServer::~UserlandFSServer()
{
if (fRequestThreads) {
for (int32 i = 0; i < kRequestThreadCount; i++)
fRequestThreads[i].PrepareTermination();
for (int32 i = 0; i < kRequestThreadCount; i++)
fRequestThreads[i].Terminate();
delete[] fRequestThreads;
}
delete fNotificationRequestPort;
delete fFileSystem;
if (fBlockCacheInitialized)
shutdown_block_cache();
if (fAddOnImage >= 0)
unload_add_on(fAddOnImage);
}
// Init
status_t
UserlandFSServer::Init(const char* fileSystem)
{
// get the add-on path
BPath addOnPath;
status_t error = find_directory(B_USER_ADDONS_DIRECTORY, &addOnPath);
if (error != B_OK)
RETURN_ERROR(error);
error = addOnPath.Append("userlandfs");
if (error != B_OK)
RETURN_ERROR(error);
error = addOnPath.Append(fileSystem);
if (error != B_OK)
RETURN_ERROR(error);
// load the add-on
fAddOnImage = load_add_on(addOnPath.Path());
if (fAddOnImage < 0)
RETURN_ERROR(fAddOnImage);
// get the symbols "fs_entry" and "api_version"
vnode_ops* fsOps;
error = get_image_symbol(fAddOnImage, "fs_entry", B_SYMBOL_TYPE_TEXT,
(void**)&fsOps);
if (error != B_OK)
RETURN_ERROR(error);
int32* apiVersion;
error = get_image_symbol(fAddOnImage, "api_version", B_SYMBOL_TYPE_DATA,
(void**)&apiVersion);
if (error != B_OK)
RETURN_ERROR(error);
// check api version
if (*apiVersion != B_CUR_FS_API_VERSION)
RETURN_ERROR(B_ERROR);
// create the file system
fFileSystem = new(nothrow) KernelUserFileSystem(fsOps);
if (!fileSystem)
RETURN_ERROR(B_NO_MEMORY);
// init the block cache
error = init_block_cache(kMaxBlockCacheBlocks, 0);
if (error != B_OK)
RETURN_ERROR(error);
fBlockCacheInitialized = true;
// create the notification request port
fNotificationRequestPort = new(nothrow) RequestPort(kRequestPortSize);
if (!fNotificationRequestPort)
RETURN_ERROR(B_NO_MEMORY);
error = fNotificationRequestPort->InitCheck();
if (error != B_OK)
RETURN_ERROR(error);
// now create the request threads
fRequestThreads = new(nothrow) RequestThread[kRequestThreadCount];
if (!fRequestThreads)
RETURN_ERROR(B_NO_MEMORY);
for (int32 i = 0; i < kRequestThreadCount; i++) {
error = fRequestThreads[i].Init(fFileSystem);
if (error != B_OK)
RETURN_ERROR(error);
}
// run the threads
for (int32 i = 0; i < kRequestThreadCount; i++)
fRequestThreads[i].Run();
// enter the debugger here, if desired
if (gServerSettings.ShallEnterDebugger())
debugger("File system ready to use.");
// finally register with the dispatcher
error = _RegisterWithDispatcher(fileSystem);
RETURN_ERROR(error);
}
// GetNotificationRequestPort
RequestPort*
UserlandFSServer::GetNotificationRequestPort()
{
if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app))
return server->fNotificationRequestPort;
return NULL;
}
// GetFileSystem
UserFileSystem*
UserlandFSServer::GetFileSystem()
{
if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app))
return server->fFileSystem;
return NULL;
}
// _RegisterWithDispatcher
status_t
UserlandFSServer::_RegisterWithDispatcher(const char* fsName)
{
// get the dispatcher messenger from the clipboard
BMessenger messenger;
BClipboard clipboard(kUserlandFSDispatcherClipboardName);
if (AutoLocker<BClipboard> locker = clipboard) {
status_t error = B_OK;
if (BMessage* data = clipboard.Data()) {
error = data->FindMessenger("messenger", &messenger);
if (error != B_OK) {
ERROR(("No dispatcher messenger in clipboard.\n"));
return error;
}
if (!messenger.IsValid()) {
ERROR(("Found dispatcher messenger not valid.\n"));
return B_ERROR;
}
} else {
ERROR(("Failed to get clipboard data container\n"));
return B_ERROR;
}
} else {
ERROR(("Failed to lock the clipboard.\n"));
return B_ERROR;
}
// get the port infos
Port::Info infos[kRequestThreadCount + 1];
infos[0] = *fNotificationRequestPort->GetPortInfo();
for (int32 i = 0; i < kRequestThreadCount; i++)
infos[i + 1] = *fRequestThreads[i].GetPortInfo();
// init an FS info
FSInfo info;
status_t error = info.SetTo(fsName, infos, kRequestThreadCount + 1);
// prepare the message
BMessage message(UFS_REGISTER_FS);
if (error == B_OK)
error = message.AddInt32("team", Team());
if (error == B_OK)
error = info.Archive(&message);
// send the message
BMessage reply;
error = messenger.SendMessage(&message, &reply);
if (error == B_OK && reply.what != UFS_REGISTER_FS_ACK) {
ERROR(("FS registration failed.\n"));
error = B_ERROR;
}
return error;
}
@@ -0,0 +1,39 @@
// UserlandFSServer.h
#ifndef USERLAND_FS_SERVER_H
#define USERLAND_FS_SERVER_H
#include <Application.h>
namespace UserlandFS {
class RequestThread;
class UserFileSystem;
class UserlandFSServer : public BApplication {
public:
UserlandFSServer(const char* signature);
virtual ~UserlandFSServer();
status_t Init(const char* fileSystem);
static RequestPort* GetNotificationRequestPort();
static UserFileSystem* GetFileSystem();
private:
status_t _RegisterWithDispatcher(const char* fsName);
private:
image_id fAddOnImage;
UserFileSystem* fFileSystem;
RequestPort* fNotificationRequestPort;
RequestThread* fRequestThreads;
bool fBlockCacheInitialized;
};
} // namespace UserlandFS
using UserlandFS::RequestThread;
using UserlandFS::UserFileSystem;
using UserlandFS::UserlandFSServer;
#endif // USERLAND_FS_SERVER_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,138 @@
// UserlandRequestHandler.h
#ifndef USERLAND_FS_USERLAND_REQUEST_HANDLER_H
#define USERLAND_FS_USERLAND_REQUEST_HANDLER_H
#include "RequestHandler.h"
namespace UserlandFSUtil {
class MountVolumeRequest;
class UnmountVolumeRequest;
class ReadFSStatRequest;
class ReadVNodeRequest;
class WriteVNodeRequest;
class ReadStatRequest;
class AccessRequest;
class OpenRequest;
class CloseRequest;
class FreeCookieRequest;
class ReadRequest;
class WalkRequest;
class OpenDirRequest;
class ReadDirRequest;
class RewindDirRequest;
class CloseDirRequest;
class FreeDirCookieRequest;
class ReadLinkRequest;
} // namespace UserlandFSUtil
namespace UserlandFS {
class UserFileSystem;
class UserlandRequestHandler : public RequestHandler {
public:
UserlandRequestHandler(
UserFileSystem* fileSystem);
UserlandRequestHandler(
UserFileSystem* fileSystem,
uint32 expectedReply);
virtual ~UserlandRequestHandler();
virtual status_t HandleRequest(Request* request);
private:
// FS
status_t _HandleRequest(MountVolumeRequest* request);
status_t _HandleRequest(UnmountVolumeRequest* request);
status_t _HandleRequest(SyncVolumeRequest* request);
status_t _HandleRequest(ReadFSStatRequest* request);
status_t _HandleRequest(WriteFSStatRequest* request);
// vnodes
status_t _HandleRequest(ReadVNodeRequest* request);
status_t _HandleRequest(WriteVNodeRequest* request);
status_t _HandleRequest(FSRemoveVNodeRequest* request);
// nodes
status_t _HandleRequest(FSyncRequest* request);
status_t _HandleRequest(ReadStatRequest* request);
status_t _HandleRequest(WriteStatRequest* request);
status_t _HandleRequest(AccessRequest* request);
// files
status_t _HandleRequest(CreateRequest* request);
status_t _HandleRequest(OpenRequest* request);
status_t _HandleRequest(CloseRequest* request);
status_t _HandleRequest(FreeCookieRequest* request);
status_t _HandleRequest(ReadRequest* request);
status_t _HandleRequest(WriteRequest* request);
status_t _HandleRequest(IOCtlRequest* request);
status_t _HandleRequest(SetFlagsRequest* request);
status_t _HandleRequest(SelectRequest* request);
status_t _HandleRequest(DeselectRequest* request);
// hard links / symlinks
status_t _HandleRequest(LinkRequest* request);
status_t _HandleRequest(UnlinkRequest* request);
status_t _HandleRequest(SymlinkRequest* request);
status_t _HandleRequest(ReadLinkRequest* request);
status_t _HandleRequest(RenameRequest* request);
// directories
status_t _HandleRequest(MkDirRequest* request);
status_t _HandleRequest(RmDirRequest* request);
status_t _HandleRequest(OpenDirRequest* request);
status_t _HandleRequest(CloseDirRequest* request);
status_t _HandleRequest(FreeDirCookieRequest* request);
status_t _HandleRequest(ReadDirRequest* request);
status_t _HandleRequest(RewindDirRequest* request);
status_t _HandleRequest(WalkRequest* request);
// attributes
status_t _HandleRequest(OpenAttrDirRequest* request);
status_t _HandleRequest(CloseAttrDirRequest* request);
status_t _HandleRequest(
FreeAttrDirCookieRequest* request);
status_t _HandleRequest(ReadAttrDirRequest* request);
status_t _HandleRequest(RewindAttrDirRequest* request);
status_t _HandleRequest(ReadAttrRequest* request);
status_t _HandleRequest(WriteAttrRequest* request);
status_t _HandleRequest(RemoveAttrRequest* request);
status_t _HandleRequest(RenameAttrRequest* request);
status_t _HandleRequest(StatAttrRequest* request);
// indices
status_t _HandleRequest(OpenIndexDirRequest* request);
status_t _HandleRequest(CloseIndexDirRequest* request);
status_t _HandleRequest(
FreeIndexDirCookieRequest* request);
status_t _HandleRequest(ReadIndexDirRequest* request);
status_t _HandleRequest(RewindIndexDirRequest* request);
status_t _HandleRequest(CreateIndexRequest* request);
status_t _HandleRequest(RemoveIndexRequest* request);
status_t _HandleRequest(RenameIndexRequest* request);
status_t _HandleRequest(StatIndexRequest* request);
// queries
status_t _HandleRequest(OpenQueryRequest* request);
status_t _HandleRequest(CloseQueryRequest* request);
status_t _HandleRequest(FreeQueryCookieRequest* request);
status_t _HandleRequest(ReadQueryRequest* request);
status_t _SendReply(RequestAllocator& allocator,
bool expectsReceipt);
private:
UserFileSystem* fFileSystem;
bool fExpectReply;
uint32 fExpectedReply;
};
} // namespace UserlandFS
using UserlandFS::UserlandRequestHandler;
#endif // USERLAND_FS_USERLAND_REQUEST_HANDLER_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,204 @@
/*
This file contains some kit-wide typedefs and structs that basically
emulate most of a normal posix-y type system. The purpose of hiding
everything behind these typedefs is to avoid inconsistencies between
various systems (such as the difference in size between off_t on BeOS
and some versions of Unix). To further avoid complications I've also
hidden the stat and dirent structs since those vary even more widely.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO (dbg@be.com).
Dominic Giampaolo
dbg@be.com
*/
#ifndef _COMPAT_H
#define _COMPAT_H
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <memory.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#ifdef __BEOS__
#include <OS.h> /* for typedefs and prototypes */
#include <image.h> /* for a few typedefs */
#include <Drivers.h> /* for various ioctl structs, etc */
#include <iovec.h> /* because we're boneheads sometimes */
#else
#include <sys/uio.h>
#endif
/*
By default (for portability reasons) the size of off_t's and ino_t's
is 32-bit. You can change the file system to be 64-bit if you want
by defining OFF_T_SIZE to be 8.
NOTE: if you change the size of OFF_T_SIZE to be 8 you will have to
go through the code and change any calls to printf() to use the
appropriate format for 64-bit integers on your OS. I have seen
4 different formats now: %Ld (BeOS and Linux), %qd (FreeBSD),
%lld (Irix) and %I64d (NT).
*/
#define OFF_T_SIZE 8
#if OFF_T_SIZE == 4
typedef long fs_off_t;
typedef long my_ino_t;
#elif OFF_T_SIZE == 8
typedef long long fs_off_t;
typedef long long my_ino_t;
#else
#error OFF_T_SIZE must be either 4 or 8.
#endif
typedef int my_dev_t;
typedef int my_mode_t;
typedef int my_uid_t;
typedef int my_gid_t;
/* This is the maximum length of a file name. Adjust it as you see fit */
#define FILE_NAME_LENGTH 256
/* This is maximum name size for naming a volume or semaphore/lock */
#define IDENT_NAME_LENGTH 32
typedef struct my_dirent {
my_dev_t d_dev;
my_ino_t d_ino;
unsigned short d_reclen;
char d_name[1];
} my_dirent_t;
typedef struct {
int fd;
struct my_dirent ent;
} MY_DIR;
/*
This is a pretty regular stat structure but it's our "internal"
version since if we depended on the host version we'd be exposed
to all sorts of nasty things (different sized ino_t's, etc).
We also can't use the normal naming style of "st_" for each field
name because on some systems fields like st_atime are really just
define's that expand to all sorts of weird stuff.
*/
struct my_stat {
my_dev_t dev; /* "device" that this file resides on */
my_ino_t ino; /* this file's inode #, unique per device */
my_mode_t mode; /* mode bits (rwx for user, group, etc) */
int nlink; /* number of hard links to this file */
my_uid_t uid; /* user id of the owner of this file */
my_gid_t gid; /* group id of the owner of this file */
fs_off_t size; /* size in bytes of this file */
size_t blksize; /* preferred block size for i/o */
time_t atime; /* last access time */
time_t mtime; /* last modification time */
time_t ctime; /* last change time, not creation time */
time_t crtime; /* creation time; not posix but useful */
};
#define MY_S_IFMT 00000170000 /* type of file */
#define MY_S_IFLNK 00000120000 /* symbolic link */
#define MY_S_IFREG 00000100000 /* regular */
#define MY_S_IFBLK 00000060000 /* block special */
#define MY_S_IFDIR 00000040000 /* directory */
#define MY_S_IFCHR 00000020000 /* character special */
#define MY_S_IFIFO 00000010000 /* fifo */
#define MY_S_ISREG(m) (((m) & MY_S_IFMT) == MY_S_IFREG)
#define MY_S_ISLNK(m) (((m) & MY_S_IFMT) == MY_S_IFLNK)
#define MY_S_ISBLK(m) (((m) & MY_S_IFMT) == MY_S_IFBLK)
#define MY_S_ISDIR(m) (((m) & MY_S_IFMT) == MY_S_IFDIR)
#define MY_S_ISCHR(m) (((m) & MY_S_IFMT) == MY_S_IFCHR)
#define MY_S_ISFIFO(m) (((m) & MY_S_IFMT) == MY_S_IFIFO)
#define MY_S_IUMSK 07777 /* user settable bits */
#define MY_S_ISUID 04000 /* set user id on execution */
#define MY_S_ISGID 02000 /* set group id on execution */
#define MY_S_ISVTX 01000 /* save swapped text even after use */
#define MY_S_IRWXU 00700 /* read, write, execute: owner */
#define MY_S_IRUSR 00400 /* read permission: owner */
#define MY_S_IWUSR 00200 /* write permission: owner */
#define MY_S_IXUSR 00100 /* execute permission: owner */
#define MY_S_IRWXG 00070 /* read, write, execute: group */
#define MY_S_IRGRP 00040 /* read permission: group */
#define MY_S_IWGRP 00020 /* write permission: group */
#define MY_S_IXGRP 00010 /* execute permission: group */
#define MY_S_IRWXO 00007 /* read, write, execute: other */
#define MY_S_IROTH 00004 /* read permission: other */
#define MY_S_IWOTH 00002 /* write permission: other */
#define MY_S_IXOTH 00001 /* execute permission: other */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef __BEOS__
typedef long sem_id;
typedef unsigned char uchar;
typedef short int16;
typedef unsigned short uint16;
typedef int int32;
typedef unsigned int uint32;
#define ulong unsigned long /* make it a #define to avoid conflicts */
typedef long long int64;
typedef unsigned long long uint64;
typedef unsigned int port_id;
typedef int bool;
typedef int image_id;
typedef long long bigtime_t;
typedef long thread_id;
typedef long status_t;
sem_id create_sem(long count, const char *name);
long delete_sem(sem_id sem);
long acquire_sem(sem_id sem);
long acquire_sem_etc(sem_id sem, int count, int flags,
bigtime_t microsecond_timeout);
long release_sem(sem_id sem);
long release_sem_etc(sem_id sem, long count, long flags);
long atomic_add(long *value, long addvalue);
int snooze(bigtime_t f);
bigtime_t system_time(void);
ssize_t read_pos(int fd, fs_off_t _pos, void *data, size_t nbytes);
ssize_t write_pos(int fd, fs_off_t _pos, const void *data, size_t nbytes);
ssize_t readv_pos(int fd, fs_off_t _pos, struct iovec *iov, int count);
ssize_t writev_pos(int fd, fs_off_t _pos, struct iovec *iov, int count);
#endif /* __BEOS__ */
void panic(const char *msg, ...);
int device_is_read_only(const char *device);
int get_device_block_size(int fd);
fs_off_t get_num_device_blocks(int fd);
int device_is_removeable(int fd);
int lock_removeable_device(int fd, bool on_or_off);
void hexdump(void *address, int size);
#endif /* _COMPAT_H */
@@ -0,0 +1,501 @@
// kernel_emu.cpp
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <fsproto.h>
#include <KernelExport.h>
#include <OS.h>
#include "RequestPort.h"
#include "Requests.h"
#include "RequestThread.h"
#include "UserlandFSServer.h"
#include "UserlandRequestHandler.h"
// Taken from the OBOS Storage Kit (storage_support.cpp)
/*! The length of the first component is returned as well as the index at
which the next one starts. These values are only valid, if the function
returns \c B_OK.
\param path the path to be parsed
\param length the variable the length of the first component is written
into
\param nextComponent the variable the index of the next component is
written into. \c 0 is returned, if there is no next component.
\return \c B_OK, if \a path is not \c NULL, \c B_BAD_VALUE otherwise
*/
static
status_t
parse_first_path_component(const char *path, int32& length,
int32& nextComponent)
{
status_t error = (path ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
int32 i = 0;
// find first '/' or end of name
for (; path[i] != '/' && path[i] != '\0'; i++);
// handle special case "/..." (absolute path)
if (i == 0 && path[i] != '\0')
i = 1;
length = i;
// find last '/' or end of name
for (; path[i] == '/' && path[i] != '\0'; i++);
if (path[i] == '\0') // this covers "" as well
nextComponent = 0;
else
nextComponent = i;
}
return error;
}
// new_path
int
new_path(const char *path, char **copy)
{
// check errors and special cases
if (!copy)
return B_BAD_VALUE;
if (!path) {
*copy = NULL;
return B_OK;
}
int32 len = strlen(path);
if (len < 1)
return B_ENTRY_NOT_FOUND;
bool appendDot = (path[len - 1] == '/');
if (appendDot)
len++;
if (len >= B_PATH_NAME_LENGTH)
return B_NAME_TOO_LONG;
// check the path components
const char *remainder = path;
int32 length, nextComponent;
do {
status_t error
= parse_first_path_component(remainder, length, nextComponent);
if (error != B_OK)
return error;
if (length >= B_FILE_NAME_LENGTH)
error = B_NAME_TOO_LONG;
remainder += nextComponent;
} while (nextComponent != 0);
// clone the path
char *copiedPath = (char*)malloc(len + 1);
if (!copiedPath)
return B_NO_MEMORY;
strcpy(copiedPath, path);
// append a dot, if desired
if (appendDot) {
copiedPath[len] = '.';
copiedPath[len] = '\0';
}
*copy = copiedPath;
return B_OK;
}
// free_path
void
free_path(char *p)
{
free(p);
}
// #pragma mark -
// get_port_and_fs
static
status_t
get_port_and_fs(RequestPort** port, UserFileSystem** fileSystem)
{
// get the request thread
RequestThread* thread = RequestThread::GetCurrentThread();
if (thread) {
*port = thread->GetPort();
*fileSystem = thread->GetFileSystem();
} else {
*port = UserlandFSServer::GetNotificationRequestPort();
*fileSystem = UserlandFSServer::GetFileSystem();
if (!*port || !*fileSystem)
return B_BAD_VALUE;
}
return B_OK;
}
// notify_listener
int
notify_listener(int op, nspace_id nsid, vnode_id vnida, vnode_id vnidb,
vnode_id vnidc, const char *name)
{
// get the request port and the file system
RequestPort* port;
UserFileSystem* fileSystem;
status_t error = get_port_and_fs(&port, &fileSystem);
if (error != B_OK)
return error;
// prepare the request
RequestAllocator allocator(port->GetPort());
NotifyListenerRequest* request;
error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->operation = op;
request->nsid = nsid;
request->vnida = vnida;
request->vnidb = vnidb;
request->vnidc = vnidc;
error = allocator.AllocateString(request->name, name);
if (error != B_OK)
return error;
// send the request
UserlandRequestHandler handler(fileSystem, NOTIFY_LISTENER_REPLY);
NotifyListenerReply* reply;
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
return error;
}
// notify_select_event
void
notify_select_event(selectsync *sync, uint32 ref)
{
// get the request port and the file system
RequestPort* port;
UserFileSystem* fileSystem;
status_t error = get_port_and_fs(&port, &fileSystem);
if (error != B_OK)
return;
// prepare the request
RequestAllocator allocator(port->GetPort());
NotifySelectEventRequest* request;
error = AllocateRequest(allocator, &request);
if (error != B_OK)
return;
request->sync = sync;
request->ref = ref;
// send the request
UserlandRequestHandler handler(fileSystem, NOTIFY_SELECT_EVENT_REPLY);
NotifySelectEventReply* reply;
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
if (error != B_OK)
return;
RequestReleaser requestReleaser(port, reply);
// process the reply: nothing to do
}
// send_notification
int
send_notification(port_id targetPort, long token, ulong what, long op,
nspace_id nsida, nspace_id nsidb, vnode_id vnida, vnode_id vnidb,
vnode_id vnidc, const char *name)
{
// get the request port and the file system
RequestPort* port;
UserFileSystem* fileSystem;
status_t error = get_port_and_fs(&port, &fileSystem);
if (error != B_OK)
return error;
// prepare the request
RequestAllocator allocator(port->GetPort());
SendNotificationRequest* request;
error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->port = targetPort;
request->token = token;
request->what = what;
request->operation = op;
request->nsida = nsida;
request->nsidb = nsidb;
request->vnida = vnida;
request->vnidb = vnidb;
request->vnidc = vnidc;
error = allocator.AllocateString(request->name, name);
if (error != B_OK)
return error;
// send the request
UserlandRequestHandler handler(fileSystem, SEND_NOTIFICATION_REPLY);
SendNotificationReply* reply;
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
return error;
}
// #pragma mark -
// get_vnode
_EXPORT
int
get_vnode(nspace_id nsid, vnode_id vnid, void** data)
{
// get the request port and the file system
RequestPort* port;
UserFileSystem* fileSystem;
status_t error = get_port_and_fs(&port, &fileSystem);
if (error != B_OK)
return error;
// prepare the request
RequestAllocator allocator(port->GetPort());
GetVNodeRequest* request;
error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->nsid = nsid;
request->vnid = vnid;
// send the request
UserlandRequestHandler handler(fileSystem, GET_VNODE_REPLY);
GetVNodeReply* reply;
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
*data = reply->node;
return error;
}
// put_vnode
_EXPORT
int
put_vnode(nspace_id nsid, vnode_id vnid)
{
// get the request port and the file system
RequestPort* port;
UserFileSystem* fileSystem;
status_t error = get_port_and_fs(&port, &fileSystem);
if (error != B_OK)
return error;
// prepare the request
RequestAllocator allocator(port->GetPort());
PutVNodeRequest* request;
error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->nsid = nsid;
request->vnid = vnid;
// send the request
UserlandRequestHandler handler(fileSystem, PUT_VNODE_REPLY);
PutVNodeReply* reply;
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
return error;
}
// new_vnode
_EXPORT
int
new_vnode(nspace_id nsid, vnode_id vnid, void* data)
{
// get the request port and the file system
RequestPort* port;
UserFileSystem* fileSystem;
status_t error = get_port_and_fs(&port, &fileSystem);
if (error != B_OK)
return error;
// prepare the request
RequestAllocator allocator(port->GetPort());
NewVNodeRequest* request;
error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->nsid = nsid;
request->vnid = vnid;
request->node = data;
// send the request
UserlandRequestHandler handler(fileSystem, NEW_VNODE_REPLY);
NewVNodeReply* reply;
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
return error;
}
// remove_vnode
_EXPORT
int
remove_vnode(nspace_id nsid, vnode_id vnid)
{
// get the request port and the file system
RequestPort* port;
UserFileSystem* fileSystem;
status_t error = get_port_and_fs(&port, &fileSystem);
if (error != B_OK)
return error;
// prepare the request
RequestAllocator allocator(port->GetPort());
RemoveVNodeRequest* request;
error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->nsid = nsid;
request->vnid = vnid;
// send the request
UserlandRequestHandler handler(fileSystem, REMOVE_VNODE_REPLY);
RemoveVNodeReply* reply;
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
return error;
}
// unremove_vnode
_EXPORT
int
unremove_vnode(nspace_id nsid, vnode_id vnid)
{
// get the request port and the file system
RequestPort* port;
UserFileSystem* fileSystem;
status_t error = get_port_and_fs(&port, &fileSystem);
if (error != B_OK)
return error;
// prepare the request
RequestAllocator allocator(port->GetPort());
UnremoveVNodeRequest* request;
error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->nsid = nsid;
request->vnid = vnid;
// send the request
UserlandRequestHandler handler(fileSystem, UNREMOVE_VNODE_REPLY);
UnremoveVNodeReply* reply;
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
return error;
}
// is_vnode_removed
_EXPORT
int
is_vnode_removed(nspace_id nsid, vnode_id vnid)
{
// get the request port and the file system
RequestPort* port;
UserFileSystem* fileSystem;
status_t error = get_port_and_fs(&port, &fileSystem);
if (error != B_OK)
return error;
// prepare the request
RequestAllocator allocator(port->GetPort());
IsVNodeRemovedRequest* request;
error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->nsid = nsid;
request->vnid = vnid;
// send the request
UserlandRequestHandler handler(fileSystem, IS_VNODE_REMOVED_REPLY);
IsVNodeRemovedReply* reply;
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
return reply->result;
}
// #pragma mark -
// kernel_debugger
_EXPORT
void
kernel_debugger(const char *message)
{
debugger(message);
}
// panic
_EXPORT
void
panic(const char *format, ...)
{
char buffer[1024];
strcpy(buffer, "PANIC: ");
int32 prefixLen = strlen(buffer);
int bufferSize = sizeof(buffer) - prefixLen;
va_list args;
va_start(args, format);
// no vsnprintf() on PPC
#if defined(__INTEL__)
vsnprintf(buffer + prefixLen, bufferSize - 1, format, args);
#else
vsprintf(buffer + prefixLen, format, args);
#endif
va_end(args);
buffer[sizeof(buffer) - 1] = '\0';
debugger(buffer);
}
// parse_expression
_EXPORT
ulong
parse_expression(char *str)
{
return 0;
}
// add_debugger_command
_EXPORT
int
add_debugger_command(char *name, int (*func)(int argc, char **argv),
char *help)
{
return B_OK;
}
// remove_debugger_command
_EXPORT
int
remove_debugger_command(char *name, int (*func)(int argc, char **argv))
{
return B_OK;
}
// kprintf
_EXPORT
void
kprintf(const char *format, ...)
{
}
// spawn_kernel_thread
thread_id
spawn_kernel_thread(thread_entry function, const char *threadName,
long priority, void *arg)
{
return spawn_thread(function, threadName, priority, arg);
}
@@ -0,0 +1,113 @@
// main.cpp
#include <stdio.h>
#include <string.h>
#include "Debug.h"
#include "ServerDefs.h"
#include "UserlandFSDispatcher.h"
#include "UserlandFSServer.h"
// server signature
static const char* kServerSignature
= "application/x-vnd.bonefish.userlandfs-server";
// usage
static const char* kUsage =
"Usage: %s <options>\n"
" %s <options> <file system>\n"
"\n"
"The first version runs the server as the dispatcher, i.e. as the singleton\n"
"app the kernel add-on contacts when it is looking for a file system.\n"
"The dispatcher uses the second version to start a server for a specific file\n"
"system.\n"
"\n"
"Options:\n"
" --debug - the file system server enters the debugger after the\n"
" userland file system add-on has been loaded and is\n"
" ready to be used. If specified for the dispatcher, it\n"
" passes the flag to all file system servers it starts.\n"
" -h, --help - print this text\n"
;
static int kArgC;
static char** kArgV;
// print_usage
void
print_usage(bool toStdErr = true)
{
fprintf((toStdErr ? stderr : stdout), kUsage, kArgV[0], kArgV[0]);
}
// main
int
main(int argc, char** argv)
{
kArgC = argc;
kArgV = argv;
// init debugging
init_debugging();
struct DebuggingExiter {
DebuggingExiter() {}
~DebuggingExiter() { exit_debugging(); }
} _;
// parse arguments
int argi = 1;
// parse options
for (; argi < argc; argi++) {
const char* arg = argv[argi];
int32 argLen = strlen(arg);
if (argLen == 0) {
print_usage();
return 1;
}
if (arg[0] != '-')
break;
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
print_usage(false);
return 0;
} else if (strcmp(arg, "--debug") == 0) {
gServerSettings.SetEnterDebugger(true);
}
}
// get file system, if any
bool dispatcher = true;
const char* fileSystem = NULL;
if (argi < argc) {
fileSystem = argv[argi++];
dispatcher = false;
}
if (argi < argc) {
print_usage();
return 1;
}
// create and init the application
BApplication* app = NULL;
status_t error = B_OK;
if (dispatcher) {
UserlandFSDispatcher* dispatcher
= new(nothrow) UserlandFSDispatcher(kServerSignature);
if (!dispatcher) {
fprintf(stderr, "Failed to create dispatcher.\n");
return 1;
}
error = dispatcher->Init();
app = dispatcher;
} else {
UserlandFSServer* server
= new(nothrow) UserlandFSServer(kServerSignature);
if (!server) {
fprintf(stderr, "Failed to create server.\n");
return 1;
}
error = server->Init(fileSystem);
app = server;
}
// run it, if everything went fine
if (error == B_OK)
app->Run();
delete app;
return 0;
}
@@ -0,0 +1,350 @@
/*
This file contains some routines that are #ifdef'ed based on what
system you're on. Currently it supports the BeOS and Unix. It
could be extended to support Windows NT but their posix support
is such a joke that it would probably be a real pain in the arse.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO (dbg@be.com).
Dominic Giampaolo
dbg@be.com
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include "compat.h"
int
device_is_read_only(const char *device)
{
#ifdef unix
return 0; /* XXXdbg should do an ioctl or something */
#else
int fd;
device_geometry dg;
fd = open(device, O_RDONLY);
if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0)
return 0;
close(fd);
return dg.read_only;
#endif
}
int
get_device_block_size(int fd)
{
#ifdef unix
return 512; /* XXXdbg should do an ioctl or something */
#else
struct stat st;
device_geometry dg;
if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0) {
if (fstat(fd, &st) < 0 || S_ISDIR(st.st_mode))
return 0;
return 512; /* just assume it's a plain old file or something */
}
return dg.bytes_per_sector;
#endif
}
fs_off_t
get_num_device_blocks(int fd)
{
#ifdef unix
struct stat st;
fstat(fd, &st); /* XXXdbg should be an ioctl or something */
return st.st_size / get_device_block_size(fd);
#else
struct stat st;
device_geometry dg;
if (ioctl(fd, B_GET_GEOMETRY, &dg) >= 0) {
return (fs_off_t)dg.cylinder_count *
(fs_off_t)dg.sectors_per_track *
(fs_off_t)dg.head_count;
}
/* if the ioctl fails, try just stat'ing in case it's a regular file */
if (fstat(fd, &st) < 0)
return 0;
return st.st_size / get_device_block_size(fd);
#endif
}
int
device_is_removeable(int fd)
{
#ifdef unix
return 0; /* XXXdbg should do an ioctl or something */
#else
device_geometry dg;
if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0) {
return 0;
}
return dg.removable;
#endif
}
#if defined(__BEOS__) && !defined(USER)
#include "scsi.h"
#endif
int
lock_removeable_device(int fd, bool on_or_off)
{
#if defined(unix) || defined(USER)
return 0; /* XXXdbg should do an ioctl or something */
#else
return ioctl(fd, B_SCSI_PREVENT_ALLOW, &on_or_off);
#endif
}
#ifndef __BEOS__
ssize_t
read_pos(int fd, fs_off_t _pos, void *data, size_t nbytes)
{
off_t pos = (off_t)_pos;
size_t ret;
if (lseek(fd, pos, SEEK_SET) < 0) {
perror("read lseek");
return EINVAL;
}
ret = read(fd, data, nbytes);
if (ret != nbytes) {
printf("read_pos: wanted %d, got %d\n", nbytes, ret);
return -1;
}
return ret;
}
ssize_t
write_pos(int fd, fs_off_t _pos, const void *data, size_t nbytes)
{
off_t pos = (off_t)_pos;
size_t ret;
if (lseek(fd, pos, SEEK_SET) < 0) {
perror("read lseek");
return EINVAL;
}
ret = write(fd, data, nbytes);
if (ret != nbytes) {
printf("write_pos: wanted %d, got %d\n", nbytes, ret);
return -1;
}
return ret;
}
#ifdef sun /* bloody wankers */
#include <sys/stream.h>
#ifdef DEF_IOV_MAX
#define MAX_IOV DEF_IOV_MAX
#else
#define MAX_IOV 16
#endif
#else /* the rest of the world... */
#define MAX_IOV 8192 /* something way bigger than we'll ever use */
#endif
ssize_t
readv_pos(int fd, fs_off_t _pos, struct iovec *iov, int count)
{
off_t pos = (off_t)_pos;
size_t amt = 0;
ssize_t ret;
struct iovec *tmpiov;
int i, n;
if (lseek(fd, pos, SEEK_SET) < 0) {
perror("read lseek");
return EINVAL;
}
i = 0;
tmpiov = iov;
while (i < count) {
if (i + MAX_IOV < count)
n = MAX_IOV;
else
n = (count - i);
ret = readv(fd, tmpiov, n);
amt += ret;
if (ret < 0)
break;
i += n;
tmpiov += n;
}
return amt;
}
ssize_t
writev_pos(int fd, fs_off_t _pos, struct iovec *iov, int count)
{
off_t pos = (off_t)_pos;
size_t amt = 0;
ssize_t ret;
struct iovec *tmpiov;
int i, n;
if (lseek(fd, pos, SEEK_SET) < 0) {
perror("read lseek");
return EINVAL;
}
i = 0;
tmpiov = iov;
while (i < count) {
if (i + MAX_IOV < count)
n = MAX_IOV;
else
n = (count - i);
ret = writev(fd, tmpiov, n);
amt += ret;
if (ret < 0)
break;
i += n;
tmpiov += n;
}
return amt;
}
#endif /* __BEOS__ */
#include <stdarg.h>
#if 0 // bonefish
void
panic(const char *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
while (TRUE)
;
}
#endif
#include "lock.h"
int
new_lock(lock *l, const char *name)
{
l->c = 1;
l->s = create_sem(0, (char *)name);
if (l->s <= 0)
return l->s;
return 0;
}
int
free_lock(lock *l)
{
delete_sem(l->s);
return 0;
}
int
new_mlock(mlock *l, long c, const char *name)
{
l->s = create_sem(c, (char *)name);
if (l->s <= 0)
return l->s;
return 0;
}
int
free_mlock(mlock *l)
{
delete_sem(l->s);
return 0;
}
#ifdef unix
#include <sys/time.h>
bigtime_t
system_time(void)
{
bigtime_t t;
struct timeval tv;
gettimeofday(&tv, NULL);
t = ((bigtime_t)tv.tv_sec * 1000000) + (bigtime_t)tv.tv_usec;
return t;
}
/*
If you're compiler/system can't deal with the version of system_time()
as defined above, use this one instead
bigtime_t
system_time(void)
{
return (bigtime_t)time(NULL);
}
*/
#endif /* unix */
#ifdef __BEOS__
#include <KernelExport.h>
void
dprintf(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
#endif
@@ -0,0 +1,170 @@
// Debug.cpp
//
// Copyright (c) 2003-2004, Ingo Weinhold ([email protected])
//
// 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.
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <OS.h>
#include "Debug.h"
/*!
\file Debug.cpp
\brief Defines debug output function with printf() signature printing
into a file.
\note The initialization is not thread safe!
*/
// locking support
static int32 init_counter = 0;
static sem_id dbg_printf_sem = -1;
static thread_id dbg_printf_thread = -1;
static int dbg_printf_nesting = 0;
#if DEBUG_PRINT
static int out = -1;
#endif
// init_debugging
status_t
init_debugging()
{
status_t error = B_OK;
if (init_counter++ == 0) {
// open the file
#if DEBUG_PRINT
out = open(DEBUG_PRINT_FILE, O_RDWR | O_CREAT | O_TRUNC);
if (out < 0) {
error = errno;
init_counter--;
}
#endif // DEBUG_PRINT
// allocate the semaphore
if (error == B_OK) {
dbg_printf_sem = create_sem(1, "dbg_printf");
if (dbg_printf_sem < 0)
error = dbg_printf_sem;
}
if (error == B_OK) {
#if DEBUG
__out("##################################################\n");
#endif
} else
exit_debugging();
}
return error;
}
// exit_debugging
status_t
exit_debugging()
{
status_t error = B_OK;
if (--init_counter == 0) {
#if DEBUG_PRINT
close(out);
out = -1;
#endif // DEBUG_PRINT
delete_sem(dbg_printf_sem);
} else
error = B_NO_INIT;
return error;
}
// dbg_printf_lock
static inline
bool
dbg_printf_lock()
{
thread_id thread = find_thread(NULL);
if (thread != dbg_printf_thread) {
if (acquire_sem(dbg_printf_sem) != B_OK)
return false;
dbg_printf_thread = thread;
}
dbg_printf_nesting++;
return true;
}
// dbg_printf_unlock
static inline
void
dbg_printf_unlock()
{
thread_id thread = find_thread(NULL);
if (thread != dbg_printf_thread)
return;
dbg_printf_nesting--;
if (dbg_printf_nesting == 0) {
dbg_printf_thread = -1;
release_sem(dbg_printf_sem);
}
}
// dbg_printf_begin
void
dbg_printf_begin()
{
dbg_printf_lock();
}
// dbg_printf_end
void
dbg_printf_end()
{
dbg_printf_unlock();
}
#if DEBUG_PRINT
// dbg_printf
void
dbg_printf(const char *format,...)
{
if (!dbg_printf_lock())
return;
char buffer[1024];
va_list args;
va_start(args, format);
// no vsnprintf() on PPC and in kernel
#if defined(__INTEL__) && USER
vsnprintf(buffer, sizeof(buffer) - 1, format, args);
#else
vsprintf(buffer, format, args);
#endif
va_end(args);
buffer[sizeof(buffer) - 1] = '\0';
write(out, buffer, strlen(buffer));
dbg_printf_unlock();
}
#endif // DEBUG_PRINT
@@ -0,0 +1,492 @@
// DriverSettings.cpp
#include <new>
#include <stdlib.h>
#include <string.h>
#include <driver_settings.h>
#include "DriverSettings.h"
#include "Referencable.h"
#include "String.h"
// The parameter values that shall be evaluated to true.
static const char* kTrueValueStrings[]
= { "1", "true", "yes", "on", "enable", "enabled" };
static const int32 kTrueValueStringCount
= sizeof(kTrueValueStrings) / sizeof(const char*);
// #pragma mark -
// #pragma mark ----- DriverParameterIterator -----
// Delegate
class DriverParameterIterator::Delegate : public Referencable {
public:
Delegate() : Referencable(true) {}
virtual ~Delegate() {}
virtual Delegate* Clone() const = 0;
virtual bool HasNext() const = 0;
virtual bool GetNext(DriverParameter* parameter) = 0;
};
// constructor
DriverParameterIterator::DriverParameterIterator()
: fDelegate(NULL)
{
}
// constructor
DriverParameterIterator::DriverParameterIterator(Delegate* delegate)
: fDelegate(delegate)
{
}
// copy constructor
DriverParameterIterator::DriverParameterIterator(
const DriverParameterIterator& other)
: fDelegate(NULL)
{
_SetTo(other.fDelegate, true);
}
// destructor
DriverParameterIterator::~DriverParameterIterator()
{
_SetTo(NULL, false);
}
// HasNext
bool
DriverParameterIterator::HasNext() const
{
return (fDelegate ? fDelegate->HasNext() : false);
}
// GetNext
bool
DriverParameterIterator::GetNext(DriverParameter* parameter)
{
if (!fDelegate)
return false;
if (fDelegate->CountReferences() > 1) {
Delegate* clone = fDelegate->Clone();
if (!clone)
return false;
_SetTo(clone, false);
}
return fDelegate->GetNext(parameter);
}
// =
DriverParameterIterator&
DriverParameterIterator::operator=(const DriverParameterIterator& other)
{
_SetTo(other.fDelegate, true);
return *this;
}
// _SetTo
void
DriverParameterIterator::_SetTo(Delegate* delegate, bool addReference)
{
if (fDelegate)
fDelegate->RemoveReference();
fDelegate = delegate;
if (fDelegate && addReference)
fDelegate->AddReference();
}
// #pragma mark -
// #pragma mark ----- DriverParameterContainer -----
// Iterator
class DriverParameterContainer::Iterator
: public DriverParameterIterator::Delegate {
public:
Iterator(const driver_parameter* parameters, int32 count)
: Delegate(),
fParameters(parameters),
fCount(count)
{
}
virtual ~Iterator()
{
}
virtual Delegate* Clone() const
{
return new(nothrow) Iterator(fParameters, fCount);
}
virtual bool HasNext() const
{
return (fParameters && fCount > 0);
}
virtual bool GetNext(DriverParameter* parameter)
{
if (fParameters && fCount > 0) {
if (parameter)
parameter->SetTo(fParameters);
fParameters++;
fCount--;
return true;
}
return false;
}
private:
const driver_parameter* fParameters;
int32 fCount;
};
// NameIterator
class DriverParameterContainer::NameIterator
: public DriverParameterIterator::Delegate {
public:
NameIterator(const driver_parameter* parameters, int32 count,
const char* name)
: Delegate(),
fParameters(parameters),
fCount(count),
fName(name)
{
_FindNext(false);
}
virtual ~NameIterator()
{
}
virtual Delegate* Clone() const
{
return new(nothrow) NameIterator(fParameters, fCount,
fName.GetString());
}
virtual bool HasNext() const
{
return (fParameters && fCount > 0);
}
virtual bool GetNext(DriverParameter* parameter)
{
if (fParameters && fCount > 0) {
if (parameter)
parameter->SetTo(fParameters);
_FindNext(true);
return true;
}
return false;
}
private:
void _FindNext(bool skipCurrent)
{
if (!fParameters || fCount < 1)
return;
if (skipCurrent) {
fParameters++;
fCount--;
}
while (fCount > 0 && fName != fParameters->name) {
fParameters++;
fCount--;
}
}
private:
const driver_parameter* fParameters;
int32 fCount;
String fName;
};
// constructor
DriverParameterContainer::DriverParameterContainer()
{
}
// destructor
DriverParameterContainer::~DriverParameterContainer()
{
}
// CountParameters
int32
DriverParameterContainer::CountParameters() const
{
int32 count;
return (GetParametersAndCount(&count) ? count : 0);
}
// GetParameters
const driver_parameter*
DriverParameterContainer::GetParameters() const
{
int32 count;
return GetParametersAndCount(&count);
}
// GetParameterAt
bool
DriverParameterContainer::GetParameterAt(int32 index,
DriverParameter* parameter) const
{
int32 count;
if (const driver_parameter* parameters = GetParametersAndCount(&count)) {
if (index >= 0 && index < count) {
if (parameter)
parameter->SetTo(parameters + index);
return true;
}
}
return false;
}
// FindParameter
bool
DriverParameterContainer::FindParameter(const char* name,
DriverParameter* parameter) const
{
if (!name)
return false;
int32 count;
if (const driver_parameter* parameters = GetParametersAndCount(&count)) {
for (int32 i = 0; i < count; i++) {
if (strcmp(name, parameters[i].name) == 0) {
if (parameter)
parameter->SetTo(parameters + i);
return true;
}
}
}
return false;
}
// GetParameterIterator
DriverParameterIterator
DriverParameterContainer::GetParameterIterator() const
{
int32 count;
if (const driver_parameter* parameters = GetParametersAndCount(&count)) {
if (Iterator* iterator = new(nothrow) Iterator(parameters, count))
return DriverParameterIterator(iterator);
}
return DriverParameterIterator();
}
// GetParameterIterator
DriverParameterIterator
DriverParameterContainer::GetParameterIterator(const char* name) const
{
int32 count;
if (const driver_parameter* parameters = GetParametersAndCount(&count)) {
NameIterator* iterator = new(nothrow) NameIterator(parameters, count,
name);
if (iterator)
return DriverParameterIterator(iterator);
}
return DriverParameterIterator();
}
// GetParameterValue
const char*
DriverParameterContainer::GetParameterValue(const char* name,
const char* unknownValue, const char* noValue) const
{
DriverParameter parameter;
if (!FindParameter(name, &parameter))
return unknownValue;
return parameter.ValueAt(0, noValue);
}
// GetBoolParameterValue
bool
DriverParameterContainer::GetBoolParameterValue(const char* name,
bool unknownValue, bool noValue) const
{
DriverParameter parameter;
if (!FindParameter(name, &parameter))
return unknownValue;
return parameter.BoolValueAt(0, noValue);
}
// GetInt32ParameterValue
int32
DriverParameterContainer::GetInt32ParameterValue(const char* name,
int32 unknownValue, int32 noValue) const
{
DriverParameter parameter;
if (!FindParameter(name, &parameter))
return unknownValue;
return parameter.Int32ValueAt(0, noValue);
}
// GetInt64ParameterValue
int64
DriverParameterContainer::GetInt64ParameterValue(const char* name,
int64 unknownValue, int64 noValue) const
{
DriverParameter parameter;
if (!FindParameter(name, &parameter))
return unknownValue;
return parameter.Int64ValueAt(0, noValue);
}
// #pragma mark -
// #pragma mark ----- DriverSettings -----
// constructor
DriverSettings::DriverSettings()
: DriverParameterContainer(),
fSettingsHandle(NULL),
fSettings(NULL)
{
}
// destructor
DriverSettings::~DriverSettings()
{
Unset();
}
// Load
status_t
DriverSettings::Load(const char* driverName)
{
Unset();
fSettingsHandle = load_driver_settings(driverName);
if (!fSettingsHandle)
return B_ENTRY_NOT_FOUND;
fSettings = get_driver_settings(fSettingsHandle);
if (!fSettings) {
Unset();
return B_ERROR;
}
return B_OK;
}
// Unset
void
DriverSettings::Unset()
{
if (fSettingsHandle)
unload_driver_settings(fSettingsHandle);
fSettingsHandle = NULL;
fSettings = NULL;
}
// GetParametersAndCount
const driver_parameter*
DriverSettings::GetParametersAndCount(int32* count) const
{
if (!fSettings)
return NULL;
*count = fSettings->parameter_count;
return fSettings->parameters;
}
// #pragma mark -
// #pragma mark ----- DriverParameter -----
// constructor
DriverParameter::DriverParameter()
: DriverParameterContainer(),
fParameter(NULL)
{
}
// destructor
DriverParameter::~DriverParameter()
{
}
// SetTo
void
DriverParameter::SetTo(const driver_parameter* parameter)
{
fParameter = parameter;
}
// GetName
const char*
DriverParameter::GetName() const
{
return (fParameter ? fParameter->name : NULL);
}
// CountValues
int32
DriverParameter::CountValues() const
{
return (fParameter ? fParameter->value_count : 0);
}
// GetValues
const char* const*
DriverParameter::GetValues() const
{
return (fParameter ? fParameter->values : 0);
}
// ValueAt
const char*
DriverParameter::ValueAt(int32 index, const char* noValue) const
{
if (!fParameter || index < 0 || index >= fParameter->value_count)
return noValue;
return fParameter->values[index];
}
// BoolValueAt
bool
DriverParameter::BoolValueAt(int32 index, bool noValue) const
{
const char* value = ValueAt(index, NULL);
if (!value)
return noValue;
for (int32 i = 0; i < kTrueValueStringCount; i++) {
if (strcmp(value, kTrueValueStrings[i]) == 0)
return true;
}
return false;
}
// Int32ValueAt
int32
DriverParameter::Int32ValueAt(int32 index, int32 noValue) const
{
const char* value = ValueAt(index, NULL);
if (!value)
return noValue;
return atol(value);
}
// Int64ValueAt
int64
DriverParameter::Int64ValueAt(int32 index, int64 noValue) const
{
const char* value = ValueAt(index, NULL);
if (!value)
return noValue;
return strtoll(value, NULL, 10);
}
// GetParametersAndCount
const driver_parameter*
DriverParameter::GetParametersAndCount(int32* count) const
{
if (!fParameter)
return NULL;
*count = fParameter->parameter_count;
return fParameter->parameters;
}
@@ -0,0 +1,60 @@
// LazyInitializable.cpp
#include "LazyInitializable.h"
// constructor
LazyInitializable::LazyInitializable()
: fInitStatus(B_NO_INIT),
fInitSemaphore(-1)
{
fInitSemaphore = create_sem(1, "init semaphore");
if (fInitSemaphore < 0)
fInitStatus = fInitSemaphore;
}
// constructor
LazyInitializable::LazyInitializable(bool init)
: fInitStatus(B_NO_INIT),
fInitSemaphore(-1)
{
if (init) {
fInitSemaphore = create_sem(1, "init semaphore");
if (fInitSemaphore < 0)
fInitStatus = fInitSemaphore;
} else
fInitStatus = B_OK;
}
// destructor
LazyInitializable::~LazyInitializable()
{
if (fInitSemaphore >= 0)
delete_sem(fInitSemaphore);
}
// Access
status_t
LazyInitializable::Access()
{
if (fInitSemaphore >= 0) {
status_t error = B_OK;
do {
error = acquire_sem(fInitSemaphore);
} while (error == B_INTERRUPTED);
if (error == B_OK) {
// we are the first: initialize
fInitStatus = FirstTimeInit();
delete_sem(fInitSemaphore);
fInitSemaphore = -1;
}
}
return fInitStatus;
}
// InitCheck
status_t
LazyInitializable::InitCheck() const
{
return fInitStatus;
}
@@ -0,0 +1,303 @@
//
// $Id: Locker.cpp,v 1.1 2002/07/09 12:24:49 ejakowatz Exp $
//
// This file contains the OpenBeOS implementation of Locker.
//
#include "Debug.h"
#include "Locker.h"
#include <OS.h>
#include <SupportDefs.h>
#ifdef USE_OPENBEOS_NAMESPACE
namespace OpenBeOS {
#endif
//
// Data Member Documentation:
//
// The "fBenaphoreCount" member is set to 1 if the Locker style is
// semaphore. If the style is benaphore, it is initialized to 0 and
// is incremented atomically when it is acquired, decremented when it
// is released. By setting the benaphore count to 1 when the style is
// semaphore, the benaphore effectively becomes a semaphore. I was able
// to determine this is what Be's implementation does by testing the
// result of the CountLockRequests() member.
//
// The "fSemaphoreID" member holds the sem_id returned from create_sem()
// when the Locker is constructed. It is used to acquire and release
// the lock regardless of the lock style (semaphore or benaphore).
//
// The "fLockOwner" member holds the thread_id of the thread which
// currently holds the lock. If no thread holds the lock, it is set to
// B_ERROR.
//
// The "fRecursiveCount" member holds a count of the number of times the
// thread holding the lock has acquired the lock without a matching unlock.
// It is basically the number of times the thread must call Unlock() before
// the lock can be acquired by a different thread.
//
//
// Constructors:
//
// All constructors just pass their arguments to InitLocker(). Note that
// the default for "name" is "some Locker" and "benaphore_style" is true.
//
Locker::Locker()
{
InitLocker("some Locker", true);
}
Locker::Locker(const char *name)
{
InitLocker(name, true);
}
Locker::Locker(bool benaphore_style)
{
InitLocker("some Locker", benaphore_style);
}
Locker::Locker(const char *name,
bool benaphore_style)
{
InitLocker(name, benaphore_style);
}
//
// This constructor is not documented. The final argument is ignored for
// now. In Be's headers, its called "for_IPC". DO NOT USE THIS
// CONSTRUCTOR!
//
Locker::Locker(const char *name,
bool benaphore_style,
bool)
{
InitLocker(name, benaphore_style);
}
//
// The destructor just deletes the semaphore. By deleting the semaphore,
// any threads waiting to acquire the Locker will be unblocked.
//
Locker::~Locker()
{
delete_sem(fSemaphoreID);
}
bool
Locker::Lock(void)
{
status_t result;
return (AcquireLock(B_INFINITE_TIMEOUT, &result));
}
status_t
Locker::LockWithTimeout(bigtime_t timeout)
{
status_t result;
AcquireLock(timeout, &result);
return result;
}
void
Locker::Unlock(void)
{
// If the thread currently holds the lockdecrement
if (IsLocked()) {
// Decrement the number of outstanding locks this thread holds
// on this Locker.
fRecursiveCount--;
// If the recursive count is now at 0, that means the Locker has
// been released by the thread.
if (fRecursiveCount == 0) {
// The Locker is no longer owned by any thread.
fLockOwner = B_ERROR;
// Decrement the benaphore count and store the undecremented
// value in oldBenaphoreCount.
int32 oldBenaphoreCount = atomic_add(&fBenaphoreCount, -1);
// If the oldBenaphoreCount is greater than 1, then there is
// at lease one thread waiting for the lock in the case of a
// benaphore.
if (oldBenaphoreCount > 1) {
// Since there are threads waiting for the lock, it must
// be released. Note, the old benaphore count will always be
// greater than 1 for a semaphore so the release is always done.
release_sem(fSemaphoreID);
}
}
}
}
thread_id
Locker::LockingThread(void) const
{
return fLockOwner;
}
bool
Locker::IsLocked(void) const
{
// This member returns true if the calling thread holds the lock.
// The easiest way to determine this is to compare the result of
// find_thread() to the fLockOwner.
return (find_thread(NULL) == fLockOwner);
}
int32
Locker::CountLocks(void) const
{
return fRecursiveCount;
}
int32
Locker::CountLockRequests(void) const
{
return fBenaphoreCount;
}
sem_id
Locker::Sem(void) const
{
return fSemaphoreID;
}
void
Locker::InitLocker(const char *name,
bool benaphore)
{
if (benaphore) {
// Because this is a benaphore, initialize the benaphore count and
// create the semaphore. Because this is a benaphore, the semaphore
// count starts at 0 (ie acquired).
fBenaphoreCount = 0;
fSemaphoreID = create_sem(0, name);
} else {
// Because this is a semaphore, initialize the benaphore count to -1
// and create the semaphore. Because this is semaphore style, the
// semaphore count starts at 1 so that one thread can acquire it and
// the next thread to acquire it will block.
fBenaphoreCount = 1;
fSemaphoreID = create_sem(1, name);
}
// bonefish: make kernel safe
#if !USER
set_sem_owner(fSemaphoreID, B_SYSTEM_TEAM);
#endif
// The lock is currently not acquired so there is no owner.
fLockOwner = B_ERROR;
// The lock is currently not acquired so the recursive count is zero.
fRecursiveCount = 0;
}
bool
Locker::AcquireLock(bigtime_t timeout,
status_t *error)
{
// By default, return no error.
*error = B_NO_ERROR;
// Only try to acquire the lock if the thread doesn't already own it.
if (!IsLocked()) {
// Increment the benaphore count and test to see if it was already greater
// than 0. If it is greater than 0, then some thread already has the
// benaphore or the style is a semaphore. Either way, we need to acquire
// the semaphore in this case.
int32 oldBenaphoreCount = atomic_add(&fBenaphoreCount, 1);
if (oldBenaphoreCount > 0) {
*error = acquire_sem_etc(fSemaphoreID, 1, B_RELATIVE_TIMEOUT,
timeout);
// Note, if the lock here does time out, the benaphore count
// is not decremented. By doing this, the benaphore count will
// never go back to zero. This means that the locking essentially
// changes to semaphore style if this was a benaphore.
//
// Doing the decrement of the benaphore count when the acquisition
// fails is a risky thing to do. If you decrement the counter at
// the same time the thread which holds the benaphore does an
// Unlock(), there is serious risk of a race condition.
//
// If the Unlock() sees a positive count and releases the semaphore
// and then the timed out thread decrements the count to 0, there
// is no one to take the semaphore. The next two threads will be
// able to acquire the benaphore at the same time! The first will
// increment the counter and acquire the lock. The second will
// acquire the semaphore and therefore the lock. Not good.
//
// This has been discussed on the becodetalk mailing list and
// Trey from Be had this to say:
//
// I looked at the LockWithTimeout() code, and it does not have
// _this_ (ie the race condition) problem. It circumvents it by
// NOT doing the atomic_add(&count, -1) if the semaphore
// acquisition fails. This means that if a
// Locker::LockWithTimeout() times out, all other Lock*() attempts
// turn into guaranteed semaphore grabs, _with_ the overhead of a
// (now) useless atomic_add().
//
// Given Trey's comments, it looks like Be took the same approach
// I did. The output of CountLockRequests() of Be's implementation
// confirms Trey's comments also.
//
// Finally some thoughts for the future with this code:
// - If 2^31 timeouts occur on a 32-bit machine (ie today),
// the benaphore count will wrap to a negative number. This
// would have unknown consequences on the ability of the Locker
// to continue to function.
//
}
}
// If the lock has successfully been acquired.
if (*error == B_NO_ERROR) {
// Set the lock owner to this thread and increment the recursive count
// by one. The recursive count is incremented because one more Unlock()
// is now required to release the lock (ie, 0 => 1, 1 => 2 etc).
fLockOwner = find_thread(NULL);
fRecursiveCount++;
}
// Return true if the lock has been acquired.
return (*error == B_NO_ERROR);
}
#ifdef USE_OPENBEOS_NAMESPACE
}
#endif
@@ -0,0 +1,101 @@
// ObjectTracker.h
#include <new>
#include <typeinfo>
#include "AutoLocker.h"
#include "Debug.h"
#include "ObjectTracker.h"
static char sTrackerBuffer[sizeof(ObjectTracker)];
// constructor
ObjectTrackable::ObjectTrackable()
{
ObjectTracker::GetDefault()->AddTrackable(this);
}
// destructor
ObjectTrackable::~ObjectTrackable()
{
ObjectTracker::GetDefault()->RemoveTrackable(this);
}
// #pragma mark -
// constructor
ObjectTracker::ObjectTracker()
: fLock("object tracker"),
fTrackables()
{
}
// destructor
ObjectTracker::~ObjectTracker()
{
ObjectTrackable* trackable = fTrackables.GetFirst();
if (trackable) {
WARN(("ObjectTracker: WARNING: There are still undeleted objects:\n"));
for (; trackable; trackable = fTrackables.GetNext(trackable)) {
WARN((" trackable: %p: type: `%s'\n", trackable,
typeid(*trackable).name()));
}
}
}
// InitDefault
ObjectTracker*
ObjectTracker::InitDefault()
{
if (!sTracker)
sTracker = new(sTrackerBuffer) ObjectTracker;
return sTracker;
}
// ExitDefault
void
ObjectTracker::ExitDefault()
{
if (sTracker) {
sTracker->~ObjectTracker();
sTracker = NULL;
}
}
// GetDefault
ObjectTracker*
ObjectTracker::GetDefault()
{
return sTracker;
}
// AddTrackable
void
ObjectTracker::AddTrackable(ObjectTrackable* trackable)
{
if (!this)
return;
if (trackable) {
AutoLocker<Locker> _(fLock);
fTrackables.Insert(trackable);
}
}
// RemoveTrackable
void
ObjectTracker::RemoveTrackable(ObjectTrackable* trackable)
{
if (!this)
return;
if (trackable) {
AutoLocker<Locker> _(fLock);
fTrackables.Remove(trackable);
}
}
// sTracker
ObjectTracker* ObjectTracker::sTracker = NULL;
@@ -0,0 +1,41 @@
// Referencable.cpp
#include "Debug.h"
#include "Referencable.h"
// constructor
Referencable::Referencable(bool deleteWhenUnreferenced)
: fReferenceCount(1),
fDeleteWhenUnreferenced(deleteWhenUnreferenced)
{
}
// destructor
Referencable::~Referencable()
{
}
// AddReference
void
Referencable::AddReference()
{
atomic_add(&fReferenceCount, 1);
}
// RemoveReference
bool
Referencable::RemoveReference()
{
bool unreferenced = (atomic_add(&fReferenceCount, -1) == 1);
if (fDeleteWhenUnreferenced && unreferenced)
delete this;
return unreferenced;
}
// CountReferences
int32
Referencable::CountReferences() const
{
return fReferenceCount;
}
@@ -0,0 +1,145 @@
// String.cpp
#include <new.h>
#include <string.h>
#include "String.h"
// strnlen
size_t
strnlen(const char *str, size_t maxLen)
{
if (str) {
size_t origMaxLen = maxLen;
while (maxLen > 0 && *str != '\0') {
maxLen--;
str++;
}
return origMaxLen - maxLen;
}
return 0;
}
/*!
\class String
\brief A very simple string class.
*/
// constructor
String::String()
: fLength(0),
fString(NULL)
{
}
// copy constructor
String::String(const String &string)
: fLength(0),
fString(NULL)
{
*this = string;
}
// constructor
String::String(const char *string, int32 length)
: fLength(0),
fString(NULL)
{
SetTo(string, length);
}
// destructor
String::~String()
{
Unset();
}
// SetTo
bool
String::SetTo(const char *string, int32 maxLength)
{
if (string) {
if (maxLength > 0)
maxLength = strnlen(string, maxLength);
else if (maxLength < 0)
maxLength = strlen(string);
}
return _SetTo(string, maxLength);
}
// Unset
void
String::Unset()
{
if (fString) {
delete[] fString;
fString = NULL;
}
fLength = 0;
}
// Truncate
void
String::Truncate(int32 newLength)
{
if (newLength < 0)
newLength = 0;
if (newLength < fLength) {
char *string = fString;
int32 len = fLength;
fString = NULL;
len = 0;
if (!_SetTo(string, newLength)) {
fString = string;
fLength = newLength;
fString[fLength] = '\0';
} else
delete[] string;
}
}
// GetString
const char *
String::GetString() const
{
if (fString)
return fString;
return "";
}
// =
String &
String::operator=(const String &string)
{
if (&string != this)
_SetTo(string.fString, string.fLength);
return *this;
}
// ==
bool
String::operator==(const String &string) const
{
return (fLength == string.fLength
&& (fLength == 0 || !strcmp(fString, string.fString)));
}
// _SetTo
bool
String::_SetTo(const char *string, int32 length)
{
bool result = true;
Unset();
if (string && length > 0) {
fString = new(nothrow) char[length + 1];
if (fString) {
memcpy(fString, string, length);
fString[length] = '\0';
fLength = length;
} else
result = false;
}
return result;
}
@@ -0,0 +1,768 @@
/* driver_settings - implements the driver settings API
**
** Initial version by Axel Dörfler, axeld@pinc-software.de
** This file may be used under the terms of the OpenBeOS License.
*/
#include <OS.h>
#include <driver_settings.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include "Compatibility.h"
#include "String.h"
// strlcat
size_t
strlcat(char *dst, char const *src, size_t s)
{
size_t i, j = strnlen(dst, s);
if (!s)
return j + strlen(src);
dst += j;
for (i = 0; ((i < s-1) && src[i]); i++) {
dst[i] = src[i];
}
dst[i] = 0;
return j + i + strlen(src + i);
}
#define SETTINGS_DIRECTORY "/boot/home/config/settings/kernel/drivers/"
#define SETTINGS_MAGIC 'DrvS'
// Those maximum values are independent from the implementation - they
// have been chosen to make the code more robust against bad files
#define MAX_SETTINGS_SIZE 32768
#define MAX_SETTINGS_LEVEL 8
#define CONTINUE_PARAMETER 1
#define NO_PARAMETER 2
typedef struct settings_handle {
void *first_buffer;
int32 magic;
struct driver_settings settings;
char *text;
} settings_handle;
enum assignment_mode {
NO_ASSIGNMENT,
ALLOW_ASSIGNMENT,
IGNORE_ASSIGNMENT
};
// Functions not part of the public API
/** Returns true for any characters that separate parameters -
* those are ignored in the input stream and won't be added
* to any words.
*/
static inline bool
is_parameter_separator(char c)
{
return c == '\n' || c == ';';
}
/** Indicates if "c" begins a new word or not.
*/
static inline bool
is_word_break(char c)
{
return isspace(c) || is_parameter_separator(c);
}
static inline bool
check_handle(settings_handle *handle)
{
if (handle == NULL
|| handle->magic != SETTINGS_MAGIC)
return false;
return true;
}
static driver_parameter *
get_parameter(settings_handle *handle, const char *name)
{
int32 i;
for (i = handle->settings.parameter_count; i-- > 0;) {
if (!strcmp(handle->settings.parameters[i].name, name))
return &handle->settings.parameters[i];
}
return NULL;
}
/** Returns the next word in the input buffer passed in via "_pos" - if
* this function returns, it will bump the input position after the word.
* It automatically cares about quoted strings and escaped characters.
* If "allowNewLine" is true, it reads over comments to get to the next
* word.
* Depending on the "assignmentMode" parameter, the '=' sign is either
* used as a work break, or not.
* The input buffer will be changed to contain the word without quotes
* or escaped characters and adds a terminating NULL byte. The "_word"
* parameter will be set to the beginning of the word.
* If the word is followed by a newline it will return B_OK, if white
* spaces follows, it will return CONTINUE_PARAMETER.
*/
static status_t
get_word(char **_pos, char **_word, int32 assignmentMode, bool allowNewLine)
{
char *pos = *_pos;
char quoted = 0;
bool newLine = false, end = false;
int escaped = 0;
bool charEscaped = false;
// Skip any white space and comments
while (pos[0]
&& ((allowNewLine && (isspace(pos[0]) || is_parameter_separator(pos[0]) || pos[0] == '#'))
|| (!allowNewLine && (pos[0] == '\t' || pos[0] == ' '))
|| (assignmentMode == ALLOW_ASSIGNMENT && pos[0] == '='))) {
// skip any comment lines
if (pos[0] == '#') {
while (pos[0] && pos[0] != '\n')
pos++;
}
pos++;
}
if (pos[0] == '}' || pos[0] == '\0') {
// if we just read some white space before an end of a
// parameter, this is just no parameter at all
*_pos = pos;
return NO_PARAMETER;
}
// Read in a word - might contain escaped (\) spaces, or it
// might also be quoted (" or ').
if (pos[0] == '"' || pos[0] == '\'') {
quoted = pos[0];
pos++;
}
*_word = pos;
while (pos[0]) {
if (charEscaped)
charEscaped = false;
else if (pos[0] == '\\') {
charEscaped = true;
escaped++;
} else if ((!quoted && (is_word_break(pos[0])
|| (assignmentMode != IGNORE_ASSIGNMENT && pos[0] == '=')))
|| (quoted && pos[0] == quoted))
break;
pos++;
}
// "String exceeds line" - missing end quote
if (quoted && pos[0] != quoted)
return B_BAD_DATA;
// last character is a backslash
if (charEscaped)
return B_BAD_DATA;
end = pos[0] == '\0';
newLine = is_parameter_separator(pos[0]) || end;
pos[0] = '\0';
// Correct name if there were any escaped characters
if (escaped) {
char *word = *_word;
int offset = 0;
while (word <= pos) {
if (word[0] == '\\') {
offset--;
word++;
}
word[offset] = word[0];
word++;
}
}
if (end) {
*_pos = pos;
return B_OK;
}
// Scan for next beginning word, open brackets, or comment start
pos++;
while (true) {
*_pos = pos;
if (!pos[0])
return B_NO_ERROR;
if (is_parameter_separator(pos[0])) {
// an open bracket '{' could follow after the first
// newline, but not later
if (newLine)
return B_NO_ERROR;
newLine = true;
} else if (pos[0] == '{' || pos[0] == '}' || pos[0] == '#')
return B_NO_ERROR;
else if (!isspace(pos[0]))
return newLine ? B_NO_ERROR : CONTINUE_PARAMETER;
pos++;
}
}
static status_t
parse_parameter(struct driver_parameter *parameter, char **_pos, int32 level)
{
char *pos = *_pos;
status_t status;
// initialize parameter first
memset(parameter, 0, sizeof(struct driver_parameter));
status = get_word(&pos, &parameter->name, NO_ASSIGNMENT, true);
if (status == CONTINUE_PARAMETER) {
while (status == CONTINUE_PARAMETER) {
char **newArray, *value;
status = get_word(&pos, &value, parameter->value_count == 0 ? ALLOW_ASSIGNMENT : IGNORE_ASSIGNMENT, false);
if (status < B_OK)
break;
// enlarge value array and save the value
newArray = realloc(parameter->values, (parameter->value_count + 1) * sizeof(char *));
if (newArray == NULL)
return B_NO_MEMORY;
parameter->values = newArray;
parameter->values[parameter->value_count++] = value;
}
}
*_pos = pos;
return status;
}
static status_t
parse_parameters(struct driver_parameter **_parameters, int *_count, char **_pos, int32 level)
{
if (level > MAX_SETTINGS_LEVEL)
return B_LINK_LIMIT;
while (true) {
struct driver_parameter parameter;
struct driver_parameter *newArray;
status_t status;
status = parse_parameter(&parameter, _pos, level);
if (status < B_OK)
return status;
if (status != NO_PARAMETER) {
driver_parameter *newParameter;
newArray = realloc(*_parameters, (*_count + 1) * sizeof(struct driver_parameter));
if (newArray == NULL)
return B_NO_MEMORY;
memcpy(&newArray[*_count], &parameter, sizeof(struct driver_parameter));
newParameter = &newArray[*_count];
*_parameters = newArray;
(*_count)++;
// check for level beginning and end
if (**_pos == '{') {
// if we go a level deeper, just start all over again...
(*_pos)++;
status = parse_parameters(&newParameter->parameters,
&newParameter->parameter_count, _pos, level + 1);
if (status < B_OK)
return status;
}
}
if ((**_pos == '}' && level > 0)
|| (**_pos == '\0' && level == 0)) {
// take the closing bracket from the stack
(*_pos)++;
return B_OK;
}
// obviously, something has gone wrong
if (**_pos == '}' || **_pos == '\0')
return B_ERROR;
}
}
static status_t
parse_settings(settings_handle *handle)
{
char *text = handle->text;
memset(&handle->settings, 0, sizeof(struct driver_settings));
// empty settings are allowed
if (text == NULL)
return B_OK;
return parse_parameters(&handle->settings.parameters, &handle->settings.parameter_count, &text, 0);
}
static void
free_parameter(struct driver_parameter *parameter)
{
int32 i;
for (i = parameter->parameter_count; i-- > 0;)
free_parameter(&parameter->parameters[i]);
free(parameter->parameters);
free(parameter->values);
}
static void
free_settings(settings_handle *handle)
{
int32 i;
for (i = handle->settings.parameter_count; i-- > 0;)
free_parameter(&handle->settings.parameters[i]);
free(handle->settings.parameters);
free(handle->text);
free(handle);
}
static settings_handle *
load_driver_settings_from_file(int file)
{
struct stat stat;
// Allocate a buffer and read the whole file into it.
// We will keep this buffer in memory, until the settings
// are unloaded.
// The driver_parameter::name field will point directly
// to this buffer.
if (fstat(file, &stat) < B_OK)
return NULL;
if (stat.st_size > B_OK && stat.st_size < MAX_SETTINGS_SIZE) {
char *text = (char *)malloc(stat.st_size + 1);
if (text != NULL && read(file, text, stat.st_size) == stat.st_size) {
settings_handle *handle = malloc(sizeof(settings_handle));
if (handle != NULL) {
text[stat.st_size] = '\0';
handle->magic = SETTINGS_MAGIC;
handle->text = text;
if (parse_settings(handle) == B_OK) {
return handle;
}
free(handle);
}
}
// "text" might be NULL here, but that's allowed
free(text);
}
return NULL;
}
static bool
put_string(char **_buffer, size_t *_bufferSize, char *string)
{
size_t length, reserved, quotes;
char *buffer = *_buffer, c;
bool quoted;
if (string == NULL)
return true;
for (length = reserved = quotes = 0; (c = string[length]) != '\0'; length++) {
if (c == '"')
quotes++;
else if (is_word_break(c))
reserved++;
}
quoted = reserved || quotes;
// update _bufferSize in any way, so that we can chain several
// of these calls without having to check the return value
// everytime
*_bufferSize -= length + (quoted ? 2 + quotes : 0);
if (*_bufferSize <= 0)
return false;
if (quoted)
*(buffer++) = '"';
for (;(c = string[0]) != '\0'; string++) {
if (c == '"')
*(buffer++) = '\\';
*(buffer++) = c;
}
if (quoted)
*(buffer++) = '"';
buffer[0] = '\0';
// update the buffer position
*_buffer = buffer;
return true;
}
static bool
put_chars(char **_buffer, size_t *_bufferSize, char *chars)
{
char *buffer = *_buffer;
size_t length;
if (chars == NULL)
return true;
length = strlen(chars);
*_bufferSize -= length;
if (*_bufferSize <= 0)
return false;
memcpy(buffer, chars, length);
buffer += length;
buffer[0] = '\0';
// update the buffer position
*_buffer = buffer;
return true;
}
static bool
put_char(char **_buffer, size_t *_bufferSize, char c)
{
char *buffer = *_buffer;
*_bufferSize -= 1;
if (*_bufferSize <= 0)
return false;
buffer[0] = c;
buffer[1] = '\0';
// update the buffer position
*_buffer = buffer + 1;
return true;
}
static void
put_level_space(char **_buffer, size_t *_bufferSize, int32 level)
{
while (level-- > 0)
put_char(_buffer, _bufferSize, '\t');
}
static bool
put_parameter(char **_buffer, size_t *_bufferSize, struct driver_parameter *parameter, int32 level, bool flat)
{
int32 i;
if (!flat)
put_level_space(_buffer, _bufferSize, level);
put_string(_buffer, _bufferSize, parameter->name);
if (flat && parameter->value_count > 0)
put_chars(_buffer, _bufferSize, " =");
for (i = 0; i < parameter->value_count; i++) {
put_char(_buffer, _bufferSize, ' ');
put_string(_buffer, _bufferSize, parameter->values[i]);
}
if (parameter->parameter_count > 0) {
put_chars(_buffer, _bufferSize, " {");
if (!flat)
put_char(_buffer, _bufferSize, '\n');
for (i = 0; i < parameter->parameter_count; i++) {
put_parameter(_buffer, _bufferSize, &parameter->parameters[i], level + 1, flat);
if (parameter->parameters[i].parameter_count == 0)
put_chars(_buffer, _bufferSize, flat ? "; " : "\n");
}
if (!flat)
put_level_space(_buffer, _bufferSize, level);
put_chars(_buffer, _bufferSize, flat ? "}" : "}\n");
}
return *_bufferSize >= 0;
}
// ToDo: the API to add an item to the driver_settings is obviously accessable
// to the kernel, so we should provide it, too (in BeOS this is used to add
// driver settings at boot time, using the safe boot menu).
//static status_t
//add_driver_parameter(const char *name, )
//{
//}
// #pragma mark -
// The public API implementation
status_t
unload_driver_settings(void *handle)
{
if (!check_handle(handle))
return B_BAD_VALUE;
free_settings(handle);
return B_OK;
}
void *
load_driver_settings(const char *driverName)
{
settings_handle *handle;
int file;
if (driverName == NULL)
return NULL;
// open the settings from the standardized location
{
char path[B_FILE_NAME_LENGTH + 64];
// ToDo: use the kernel's find_directory for this
strcpy(path, SETTINGS_DIRECTORY);
strlcat(path, driverName, sizeof(path));
file = open(path, O_RDONLY);
}
if (file < B_OK)
return NULL;
handle = load_driver_settings_from_file(file);
close(file);
return (void *)handle;
}
/** Loads a driver settings file using the full path, instead of
* only defining the leaf name (as load_driver_settings() does).
* I am not sure if this function is really necessary - I would
* probably prefer something like a search order (if it's not
* an absolute path):
* ~/config/settings/kernel/driver
* current directory
* That would render this function useless.
*/
#if 0
void *
load_driver_settings_from_path(const char *path)
{
settings_handle *handle;
int file;
if (path == NULL)
return NULL;
file = open(path, O_RDONLY);
if (file < B_OK)
return NULL;
handle = load_driver_settings_from_file(file);
close(file);
return (void *)handle;
}
#endif
/** Returns a new driver_settings handle that has the parsed contents
* of the passed string.
* You can get an empty driver_settings object when you pass NULL as
* the "settingsString" parameter.
*/
void *
parse_driver_settings_string(const char *settingsString)
{
// we simply copy the whole string to use it as our internal buffer
char *text = strdup(settingsString);
if (settingsString == NULL || text != NULL) {
settings_handle *handle = malloc(sizeof(settings_handle));
if (handle != NULL) {
handle->magic = SETTINGS_MAGIC;
handle->text = text;
if (parse_settings(handle) == B_OK)
return handle;
free(handle);
}
free(text);
}
return NULL;
}
/** This function prints out a driver settings structure to a human
* readable string.
* It's either in standard style or the single line style speficied
* by the "flat" parameter.
* If the buffer is too small to hold the string, B_BUFFER_OVERFLOW
* is returned, and the needed amount of bytes if placed in the
* "_bufferSize" parameter.
* If the "handle" parameter is not a valid driver settings handle, or
* the "buffer" parameter is NULL, B_BAD_VALUE is returned.
*/
status_t
get_driver_settings_string(void *_handle, char *buffer, size_t *_bufferSize, bool flat)
{
settings_handle *handle = (settings_handle *)_handle;
size_t bufferSize = *_bufferSize;
int32 i;
if (!check_handle(handle) || !buffer || *_bufferSize == 0)
return B_BAD_VALUE;
for (i = 0; i < handle->settings.parameter_count; i++) {
put_parameter(&buffer, &bufferSize, &handle->settings.parameters[i], 0, flat);
}
*_bufferSize -= bufferSize;
return bufferSize >= 0 ? B_OK : B_BUFFER_OVERFLOW;
}
/** Matches the first value of the parameter matching "keyName" with a set
* of boolean values like 1/true/yes/on/enabled/...
* Returns "unknownValue" if the parameter could not be found or doesn't
* have any valid boolean setting, and "noArgValue" if the parameter
* doesn't have any values.
* Also returns "unknownValue" if the handle passed in was not valid.
*/
bool
get_driver_boolean_parameter(void *handle, const char *keyName, bool unknownValue, bool noArgValue)
{
driver_parameter *parameter;
char *boolean;
if (!check_handle(handle))
return unknownValue;
// check for the parameter
if ((parameter = get_parameter(handle, keyName)) == NULL)
return unknownValue;
// check for the argument
if (parameter->value_count <= 0)
return noArgValue;
boolean = parameter->values[0];
if (!strcmp(boolean, "1")
|| !strcasecmp(boolean, "true")
|| !strcasecmp(boolean, "yes")
|| !strcasecmp(boolean, "on")
|| !strcasecmp(boolean, "enable")
|| !strcasecmp(boolean, "enabled"))
return true;
if (!strcmp(boolean, "0")
|| !strcasecmp(boolean, "false")
|| !strcasecmp(boolean, "no")
|| !strcasecmp(boolean, "off")
|| !strcasecmp(boolean, "disable")
|| !strcasecmp(boolean, "disabled"))
return false;
// if no known keyword is found, "unknownValue" is returned
return unknownValue;
}
const char *
get_driver_parameter(void *handle, const char *keyName, const char *unknownValue, const char *noArgValue)
{
struct driver_parameter *parameter;
if (!check_handle(handle))
return unknownValue;
// check for the parameter
if ((parameter = get_parameter(handle, keyName)) == NULL)
return unknownValue;
// check for the argument
if (parameter->value_count <= 0)
return noArgValue;
return parameter->values[0];
}
const driver_settings *
get_driver_settings(void *handle)
{
if (!check_handle(handle))
return NULL;
return &((settings_handle *)handle)->settings;
}
// this creates an alias of the above function
// unload_driver_settings() is the same as delete_driver_settings()
#ifndef __MWERKS__
extern __typeof(unload_driver_settings) delete_driver_settings __attribute__ ((alias ("unload_driver_settings")));
#endif
@@ -0,0 +1,15 @@
SubDir HAIKU_TOP src tests add-ons kernel file_systems userlandfs r5 src
ufs_mount ;
SetSubDirSupportedPlatforms r5 bone dano ;
local userlandFSTop = [ FDirName $(HAIKU_TOP) src tests add-ons kernel
file_systems userlandfs r5 ] ;
local userlandFSIncludes = [ FDirName $(userlandFSTop) headers ] ;
SubDirHdrs [ FDirName $(userlandFSIncludes) private ] ;
SEARCH_SOURCE += [ FDirName $(userlandFSTop) src shared ] ;
Application <test>ufs_mount : ufs_mount.cpp : be ;
@@ -0,0 +1,50 @@
// ufs_mount.cpp
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <String.h>
const char* kUsage =
"Usage: ufs_mount <file system> <device> <mount point> [ <parameters> ]\n"
;
// print_usage
void
print_usage(bool error = true)
{
fprintf((error ? stderr : stdout), kUsage);
}
// main
int
main(int argc, char** argv)
{
// check and get the parameters
if (argc < 4 || argc > 5) {
print_usage();
return 1;
}
const char* fileSystem = argv[1];
const char* device = argv[2];
const char* mountPoint = argv[3];
const char* fsParameters = (argc >= 5 ? argv[4] : NULL);
// get prepare the parameters for the mount() call
if (strlen(device) == 0)
device = NULL;
BString parameters(fileSystem);
if (fsParameters)
parameters << ' ' << fsParameters;
// mount
ulong flags = 0;
printf("mount('userlandfs', '%s', '%s', %lu, '%s', %ld)\n", mountPoint, device,
flags, parameters.String(), parameters.Length() + 1);
if (mount("userlandfs", mountPoint, device, flags,
(void*)parameters.String(), parameters.Length() + 1) < 0) {
fprintf(stderr, "mounting failed: %s\n", strerror(errno));
return 1;
}
return 0;
}