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:
@@ -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_ */
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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 ¶m = container->parameters[cookie];
|
||||||
|
if (!strcmp(param.name, name))
|
||||||
|
parameter = ¶m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 ¶m = 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(¤tRequest, 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, ¶meter))
|
||||||
|
return unknownValue;
|
||||||
|
return parameter.ValueAt(0, noValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBoolParameterValue
|
||||||
|
bool
|
||||||
|
DriverParameterContainer::GetBoolParameterValue(const char* name,
|
||||||
|
bool unknownValue, bool noValue) const
|
||||||
|
{
|
||||||
|
DriverParameter parameter;
|
||||||
|
if (!FindParameter(name, ¶meter))
|
||||||
|
return unknownValue;
|
||||||
|
return parameter.BoolValueAt(0, noValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInt32ParameterValue
|
||||||
|
int32
|
||||||
|
DriverParameterContainer::GetInt32ParameterValue(const char* name,
|
||||||
|
int32 unknownValue, int32 noValue) const
|
||||||
|
{
|
||||||
|
DriverParameter parameter;
|
||||||
|
if (!FindParameter(name, ¶meter))
|
||||||
|
return unknownValue;
|
||||||
|
return parameter.Int32ValueAt(0, noValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInt64ParameterValue
|
||||||
|
int64
|
||||||
|
DriverParameterContainer::GetInt64ParameterValue(const char* name,
|
||||||
|
int64 unknownValue, int64 noValue) const
|
||||||
|
{
|
||||||
|
DriverParameter parameter;
|
||||||
|
if (!FindParameter(name, ¶meter))
|
||||||
|
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, ¶meter->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(¶meter, _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], ¶meter, 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(¶meter->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, ¶meter->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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user