libvtreefs: API changes/extensions, part 1
- move primary I/O buffer into vtreefs; change read hook API; - add hooks for write, truncate, symlink, mknod, unlink, chmod/chown; - modernize message_hook; - change procfs, devman, gpio accordingly; Change-Id: I9f0669e41195efa3253032e95d93f0a78e9d68d6
This commit is contained in:
parent
693ad767e8
commit
5eefd0fec2
21 changed files with 655 additions and 358 deletions
|
@ -71,6 +71,9 @@ static struct inode_stat default_file_stat = {
|
||||||
.dev = NO_DEV,
|
.dev = NO_DEV,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Buffer size for read requests */
|
||||||
|
#define DATA_SIZE 26
|
||||||
|
|
||||||
int
|
int
|
||||||
add_gpio_inode(char *name, int nr, int mode)
|
add_gpio_inode(char *name, int nr, int mode)
|
||||||
{
|
{
|
||||||
|
@ -206,14 +209,12 @@ init_hook(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static ssize_t
|
||||||
read_hook
|
read_hook
|
||||||
(struct inode *inode, off_t offset, char **ptr, size_t * len,
|
(struct inode *inode, char *ptr, size_t len, off_t offset, cbdata_t cbdata)
|
||||||
cbdata_t cbdata)
|
|
||||||
{
|
{
|
||||||
/* This hook will be called every time a regular file is read. We use
|
/* This hook will be called every time a regular file is read. We use
|
||||||
* it to dyanmically generate the contents of our file. */
|
* it to dyanmically generate the contents of our file. */
|
||||||
static char data[26];
|
|
||||||
int value;
|
int value;
|
||||||
struct gpio_cbdata *gpio_cbdata = (struct gpio_cbdata *) cbdata;
|
struct gpio_cbdata *gpio_cbdata = (struct gpio_cbdata *) cbdata;
|
||||||
assert(gpio_cbdata->gpio != NULL);
|
assert(gpio_cbdata->gpio != NULL);
|
||||||
|
@ -222,53 +223,42 @@ static int
|
||||||
|| gpio_cbdata->type == GPIO_CB_OFF) {
|
|| gpio_cbdata->type == GPIO_CB_OFF) {
|
||||||
/* turn on or off */
|
/* turn on or off */
|
||||||
if (gpio_set(gpio_cbdata->gpio,
|
if (gpio_set(gpio_cbdata->gpio,
|
||||||
(gpio_cbdata->type == GPIO_CB_ON) ? 1 : 0)) {
|
(gpio_cbdata->type == GPIO_CB_ON) ? 1 : 0))
|
||||||
*len = 0;
|
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
return 0;
|
||||||
*len = 0;
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpio_cbdata->type == GPIO_CB_INTR_READ) {
|
if (gpio_cbdata->type == GPIO_CB_INTR_READ) {
|
||||||
/* reading interrupt */
|
/* reading interrupt */
|
||||||
if (gpio_intr_read(gpio_cbdata->gpio, &value)) {
|
if (gpio_intr_read(gpio_cbdata->gpio, &value))
|
||||||
*len = 0;
|
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* reading */
|
/* reading */
|
||||||
if (gpio_read(gpio_cbdata->gpio, &value)) {
|
if (gpio_read(gpio_cbdata->gpio, &value))
|
||||||
*len = 0;
|
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
}
|
snprintf(ptr, DATA_SIZE, "%d\n", value);
|
||||||
snprintf(data, 26, "%d\n", value);
|
len = strlen(ptr);
|
||||||
|
|
||||||
/* If the offset is beyond the end of the string, return EOF. */
|
/* If the offset is at or beyond the end of the string, return EOF. */
|
||||||
if (offset > strlen(data)) {
|
if (offset >= len)
|
||||||
*len = 0;
|
return 0;
|
||||||
|
|
||||||
return OK;
|
/* Otherwise, we may have to move the data to the start of ptr. */
|
||||||
|
if (offset > 0) {
|
||||||
|
len -= offset;
|
||||||
|
|
||||||
|
memmove(ptr, &ptr[offset], len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, return a pointer into 'data'. If necessary, bound the
|
/* Return the resulting length. */
|
||||||
* returned length to the length of the rest of the string. Note that
|
return len;
|
||||||
* 'data' has to be static, because it will be used after this
|
|
||||||
* function returns. */
|
|
||||||
*ptr = data + offset;
|
|
||||||
|
|
||||||
if (*len > strlen(data) - offset)
|
|
||||||
*len = strlen(data) - offset;
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
message_hook(message * m)
|
message_hook(message * m, int __unused ipc_status)
|
||||||
{
|
{
|
||||||
gpio_intr_message(m);
|
gpio_intr_message(m);
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -294,7 +284,7 @@ main(int argc, char **argv)
|
||||||
root_stat.dev = NO_DEV;
|
root_stat.dev = NO_DEV;
|
||||||
|
|
||||||
/* limit the number of indexed entries */
|
/* limit the number of indexed entries */
|
||||||
start_vtreefs(&hooks, 30, &root_stat, 0);
|
start_vtreefs(&hooks, 30, &root_stat, 0, DATA_SIZE);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,25 +3,25 @@
|
||||||
#include "inc.h"
|
#include "inc.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#define BUF_SIZE 4096
|
static char *buf;
|
||||||
|
static size_t left, used;
|
||||||
static char buf[BUF_SIZE + 1];
|
|
||||||
static size_t off, left, used;
|
|
||||||
static off_t skip;
|
static off_t skip;
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* buf_init *
|
* buf_init *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void buf_init(off_t start, size_t len)
|
void buf_init(char *ptr, size_t len, off_t start)
|
||||||
{
|
{
|
||||||
/* Initialize the buffer for fresh use. The first 'start' bytes of the
|
/* Initialize the buffer for fresh use. The output is to be stored into
|
||||||
* produced output are to be skipped. After that, up to a total of
|
* 'ptr' which is BUF_SIZE bytes in size, since that is the size we
|
||||||
* 'len' bytes are requested.
|
* requested. Due to the way vsnprintf works, we cannot use the last
|
||||||
|
* byte of this buffer. The first 'start' bytes of the produced output
|
||||||
|
* are to be skipped. After that, a total of 'len' bytes are requested.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
buf = ptr;
|
||||||
skip = start;
|
skip = start;
|
||||||
left = MIN(len, BUF_SIZE);
|
left = MIN(len, BUF_SIZE - 1);
|
||||||
off = 0;
|
|
||||||
used = 0;
|
used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,21 +40,23 @@ void buf_printf(char *fmt, ...)
|
||||||
|
|
||||||
/* There is no way to estimate how much space the result will take, so
|
/* There is no way to estimate how much space the result will take, so
|
||||||
* we need to produce the string even when skipping part of the start.
|
* we need to produce the string even when skipping part of the start.
|
||||||
* If part of the result is to be skipped, do not memcpy; instead, save
|
|
||||||
* the offset of where the result starts within the buffer.
|
|
||||||
*
|
|
||||||
* The null terminating character is not part of the result, so room
|
* The null terminating character is not part of the result, so room
|
||||||
* must be given for it to be stored after completely filling up the
|
* must be given for it to be stored after completely filling up the
|
||||||
* requested part of the buffer.
|
* requested part of the buffer.
|
||||||
*/
|
*/
|
||||||
max = MIN(skip + left, BUF_SIZE);
|
max = MIN(skip + left + 1, BUF_SIZE);
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
len = vsnprintf(&buf[off + used], max + 1, fmt, args);
|
len = vsnprintf(&buf[used], max, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
|
/* The snprintf family returns the number of bytes that would be stored
|
||||||
|
* if the buffer were large enough, excluding the null terminator.
|
||||||
|
*/
|
||||||
|
if (len >= BUF_SIZE)
|
||||||
|
len = BUF_SIZE - 1;
|
||||||
|
|
||||||
if (skip > 0) {
|
if (skip > 0) {
|
||||||
assert(off == 0);
|
|
||||||
assert(used == 0);
|
assert(used == 0);
|
||||||
|
|
||||||
if (skip >= len) {
|
if (skip >= len) {
|
||||||
|
@ -63,16 +65,15 @@ void buf_printf(char *fmt, ...)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
off = skip;
|
memmove(buf, &buf[skip], len - skip);
|
||||||
if (left > BUF_SIZE - off)
|
|
||||||
left = BUF_SIZE - off;
|
len -= skip;
|
||||||
len -= off;
|
|
||||||
skip = 0;
|
skip = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(skip == 0);
|
assert(skip == 0);
|
||||||
assert(len >= 0);
|
assert(len >= 0);
|
||||||
assert((long) left >= 0);
|
assert((ssize_t) left >= 0);
|
||||||
|
|
||||||
if (len > (ssize_t) left)
|
if (len > (ssize_t) left)
|
||||||
len = left;
|
len = left;
|
||||||
|
@ -107,22 +108,20 @@ void buf_append(char *data, size_t len)
|
||||||
if (len > left)
|
if (len > left)
|
||||||
len = left;
|
len = left;
|
||||||
|
|
||||||
memcpy(&buf[off + used], data, len);
|
memcpy(&buf[used], data, len);
|
||||||
|
|
||||||
used += len;
|
used += len;
|
||||||
left -= len;
|
left -= len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* buf_get *
|
* buf_result *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
size_t buf_get(char **ptr)
|
ssize_t buf_result(void)
|
||||||
{
|
{
|
||||||
/* Return the buffer's starting address and the length of the used
|
/* Return the resulting number of bytes produced, not counting the
|
||||||
* part, not counting the trailing null character for the latter.
|
* trailing null character in the buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
*ptr = &buf[off];
|
|
||||||
|
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,4 +30,7 @@
|
||||||
#define DIR_ALL_MODE (S_IFDIR | 0555) /* world-accessible directory */
|
#define DIR_ALL_MODE (S_IFDIR | 0555) /* world-accessible directory */
|
||||||
#define LNK_ALL_MODE (S_IFLNK | 0777) /* symbolic link */
|
#define LNK_ALL_MODE (S_IFLNK | 0777) /* symbolic link */
|
||||||
|
|
||||||
|
/* Size of the I/O buffer. */
|
||||||
|
#define BUF_SIZE 4097 /* 4KB+1 (see buf.c) */
|
||||||
|
|
||||||
#endif /* _PROCFS_CONST_H */
|
#endif /* _PROCFS_CONST_H */
|
||||||
|
|
|
@ -7,13 +7,11 @@ static void init_hook(void);
|
||||||
|
|
||||||
/* The hook functions that will be called by VTreeFS. */
|
/* The hook functions that will be called by VTreeFS. */
|
||||||
static struct fs_hooks hooks = {
|
static struct fs_hooks hooks = {
|
||||||
init_hook,
|
.init_hook = init_hook,
|
||||||
NULL, /* cleanup_hook */
|
.lookup_hook = lookup_hook,
|
||||||
lookup_hook,
|
.getdents_hook = getdents_hook,
|
||||||
getdents_hook,
|
.read_hook = read_hook,
|
||||||
read_hook,
|
.rdlink_hook = rdlink_hook,
|
||||||
rdlink_hook,
|
|
||||||
NULL /* message_hook */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -90,7 +88,7 @@ int main(void)
|
||||||
stat.dev = NO_DEV;
|
stat.dev = NO_DEV;
|
||||||
|
|
||||||
/* Start VTreeFS. */
|
/* Start VTreeFS. */
|
||||||
start_vtreefs(&hooks, NR_INODES, &stat, NR_PROCS + NR_TASKS);
|
start_vtreefs(&hooks, NR_INODES, &stat, NR_PROCS + NR_TASKS, BUF_SIZE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,18 @@
|
||||||
#define _PROCFS_PROTO_H
|
#define _PROCFS_PROTO_H
|
||||||
|
|
||||||
/* buf.c */
|
/* buf.c */
|
||||||
void buf_init(off_t start, size_t len);
|
void buf_init(char *ptr, size_t len, off_t start);
|
||||||
void buf_printf(char *fmt, ...);
|
void buf_printf(char *fmt, ...);
|
||||||
void buf_append(char *data, size_t len);
|
void buf_append(char *data, size_t len);
|
||||||
size_t buf_get(char **ptr);
|
ssize_t buf_result(void);
|
||||||
|
|
||||||
/* tree.c */
|
/* tree.c */
|
||||||
int init_tree(void);
|
int init_tree(void);
|
||||||
int lookup_hook(struct inode *parent, char *name, cbdata_t cbdata);
|
int lookup_hook(struct inode *parent, char *name, cbdata_t cbdata);
|
||||||
int getdents_hook(struct inode *inode, cbdata_t cbdata);
|
int getdents_hook(struct inode *inode, cbdata_t cbdata);
|
||||||
int read_hook(struct inode *inode, off_t offset, char **ptr, size_t
|
ssize_t read_hook(struct inode *inode, char *ptr, size_t len, off_t off,
|
||||||
*len, cbdata_t cbdata);
|
cbdata_t cbdata);
|
||||||
int rdlink_hook(struct inode *inode, char *ptr, size_t max, cbdata_t
|
int rdlink_hook(struct inode *inode, char *ptr, size_t max, cbdata_t cbdata);
|
||||||
cbdata);
|
|
||||||
|
|
||||||
/* util.c */
|
/* util.c */
|
||||||
int procfs_getloadavg(struct load *loadavg, int nelem);
|
int procfs_getloadavg(struct load *loadavg, int nelem);
|
||||||
|
|
|
@ -494,14 +494,14 @@ int getdents_hook(struct inode *node, cbdata_t UNUSED(cbdata))
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* read_hook *
|
* read_hook *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int read_hook(struct inode *node, off_t off, char **ptr,
|
ssize_t read_hook(struct inode *node, char *ptr, size_t len, off_t off,
|
||||||
size_t *len, cbdata_t cbdata)
|
cbdata_t cbdata)
|
||||||
{
|
{
|
||||||
/* Regular file read hook. Call the appropriate callback function to
|
/* Regular file read hook. Call the appropriate callback function to
|
||||||
* generate and return the data.
|
* generate and return the data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
buf_init(off, *len);
|
buf_init(ptr, len, off);
|
||||||
|
|
||||||
/* Populate the buffer with the proper content. */
|
/* Populate the buffer with the proper content. */
|
||||||
if (get_inode_index(node) != NO_INDEX) {
|
if (get_inode_index(node) != NO_INDEX) {
|
||||||
|
@ -510,9 +510,7 @@ int read_hook(struct inode *node, off_t off, char **ptr,
|
||||||
((void (*) (void)) cbdata)();
|
((void (*) (void)) cbdata)();
|
||||||
}
|
}
|
||||||
|
|
||||||
*len = buf_get(ptr);
|
return buf_result();
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
@ -25,11 +25,21 @@ struct fs_hooks {
|
||||||
void (*cleanup_hook)(void);
|
void (*cleanup_hook)(void);
|
||||||
int (*lookup_hook)(struct inode *inode, char *name, cbdata_t cbdata);
|
int (*lookup_hook)(struct inode *inode, char *name, cbdata_t cbdata);
|
||||||
int (*getdents_hook)(struct inode *inode, cbdata_t cbdata);
|
int (*getdents_hook)(struct inode *inode, cbdata_t cbdata);
|
||||||
int (*read_hook)(struct inode *inode, off_t offset, char **ptr,
|
ssize_t (*read_hook)(struct inode *inode, char *ptr, size_t len,
|
||||||
size_t *len, cbdata_t cbdata);
|
off_t off, cbdata_t cbdata);
|
||||||
|
ssize_t (*write_hook)(struct inode *inode, char *ptr, size_t max,
|
||||||
|
off_t off, cbdata_t cbdata);
|
||||||
|
int (*trunc_hook)(struct inode *inode, off_t offset, cbdata_t cbdata);
|
||||||
|
int (*mknod_hook)(struct inode *inode, char *name,
|
||||||
|
struct inode_stat *stat, cbdata_t cbdata);
|
||||||
|
int (*unlink_hook)(struct inode *inode, cbdata_t cbdata);
|
||||||
|
int (*slink_hook)(struct inode *inode, char *name,
|
||||||
|
struct inode_stat *stat, char *path, cbdata_t cbdata);
|
||||||
int (*rdlink_hook)(struct inode *inode, char *ptr, size_t max,
|
int (*rdlink_hook)(struct inode *inode, char *ptr, size_t max,
|
||||||
cbdata_t cbdata);
|
cbdata_t cbdata);
|
||||||
int (*message_hook)(message *m);
|
int (*chstat_hook)(struct inode *inode, struct inode_stat *stat,
|
||||||
|
cbdata_t cbdata);
|
||||||
|
void (*message_hook)(message *m, int ipc_status);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct inode *add_inode(struct inode *parent, const char *name,
|
extern struct inode *add_inode(struct inode *parent, const char *name,
|
||||||
|
@ -55,6 +65,6 @@ extern void get_inode_stat(const struct inode *inode, struct inode_stat *stat);
|
||||||
extern void set_inode_stat(struct inode *inode, struct inode_stat *stat);
|
extern void set_inode_stat(struct inode *inode, struct inode_stat *stat);
|
||||||
|
|
||||||
extern void start_vtreefs(struct fs_hooks *hooks, unsigned int nr_inodes,
|
extern void start_vtreefs(struct fs_hooks *hooks, unsigned int nr_inodes,
|
||||||
struct inode_stat *stat, index_t nr_indexed_entries);
|
struct inode_stat *stat, index_t nr_indexed_entries, size_t buf_size);
|
||||||
|
|
||||||
#endif /* _MINIX_VTREEFS_H */
|
#endif /* _MINIX_VTREEFS_H */
|
||||||
|
|
|
@ -7,11 +7,11 @@ CPPFLAGS+= -D_MINIX_SYSTEM
|
||||||
LIB= vtreefs
|
LIB= vtreefs
|
||||||
|
|
||||||
SRCS= \
|
SRCS= \
|
||||||
|
file.c \
|
||||||
inode.c \
|
inode.c \
|
||||||
link.c \
|
link.c \
|
||||||
mount.c \
|
mount.c \
|
||||||
path.c \
|
path.c \
|
||||||
read.c \
|
|
||||||
sdbm.c \
|
sdbm.c \
|
||||||
stadir.c \
|
stadir.c \
|
||||||
table.c \
|
table.c \
|
||||||
|
|
293
minix/lib/libvtreefs/file.c
Normal file
293
minix/lib/libvtreefs/file.c
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
/* VTreeFS - file.c - file and directory I/O */
|
||||||
|
|
||||||
|
#include "inc.h"
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#define GETDENTS_BUFSIZ 4096
|
||||||
|
|
||||||
|
static char *buf = NULL;
|
||||||
|
static size_t bufsize = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the main buffer used for I/O. Return OK or an error code.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
init_buf(size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* A default buffer size, for at least getdents. */
|
||||||
|
if (size < GETDENTS_BUFSIZ)
|
||||||
|
size = GETDENTS_BUFSIZ;
|
||||||
|
|
||||||
|
if ((buf = malloc(size)) == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
bufsize = size;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free up the I/O buffer.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cleanup_buf(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
buf = NULL;
|
||||||
|
bufsize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read from a file.
|
||||||
|
*/
|
||||||
|
ssize_t
|
||||||
|
fs_read(ino_t ino_nr, struct fsdriver_data * data, size_t bytes,
|
||||||
|
off_t pos, int __unused call)
|
||||||
|
{
|
||||||
|
struct inode *node;
|
||||||
|
size_t off, chunk;
|
||||||
|
ssize_t r, len;
|
||||||
|
|
||||||
|
/* Try to get inode by its inode number. */
|
||||||
|
if ((node = find_inode(ino_nr)) == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
/* Check whether the node is a regular file. */
|
||||||
|
if (!S_ISREG(node->i_stat.mode))
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
/* For deleted files or with no read hook, feign an empty file. */
|
||||||
|
if (is_inode_deleted(node) || vtreefs_hooks->read_hook == NULL)
|
||||||
|
return 0; /* EOF */
|
||||||
|
|
||||||
|
assert(buf != NULL);
|
||||||
|
assert(bufsize > 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call the read hook to fill the result buffer, repeatedly for as long
|
||||||
|
* as 1) the request is not yet fully completed, and 2) the read hook
|
||||||
|
* fills the entire buffer.
|
||||||
|
*/
|
||||||
|
for (off = 0; off < bytes; ) {
|
||||||
|
/* Get the next result chunk by calling the read hook. */
|
||||||
|
chunk = bytes - off;
|
||||||
|
if (chunk > bufsize)
|
||||||
|
chunk = bufsize;
|
||||||
|
|
||||||
|
len = vtreefs_hooks->read_hook(node, buf, chunk, pos,
|
||||||
|
get_inode_cbdata(node));
|
||||||
|
|
||||||
|
/* Copy any resulting data to user space. */
|
||||||
|
if (len > 0)
|
||||||
|
r = fsdriver_copyout(data, off, buf, len);
|
||||||
|
else
|
||||||
|
r = len; /* EOF or error */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If an error occurred, but we already produced some output,
|
||||||
|
* return a partial result. Otherwise return the error.
|
||||||
|
*/
|
||||||
|
if (r < 0)
|
||||||
|
return (off > 0) ? off : r;
|
||||||
|
|
||||||
|
off += len;
|
||||||
|
pos += len;
|
||||||
|
|
||||||
|
if ((size_t)len < bufsize)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write to a file.
|
||||||
|
*/
|
||||||
|
ssize_t
|
||||||
|
fs_write(ino_t ino_nr, struct fsdriver_data * data, size_t bytes, off_t pos,
|
||||||
|
int __unused call)
|
||||||
|
{
|
||||||
|
struct inode *node;
|
||||||
|
size_t off, chunk;
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
if ((node = find_inode(ino_nr)) == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (!S_ISREG(node->i_stat.mode))
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (is_inode_deleted(node) || vtreefs_hooks->write_hook == NULL)
|
||||||
|
return EACCES;
|
||||||
|
|
||||||
|
if (bytes == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
assert(buf != NULL);
|
||||||
|
assert(bufsize > 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call the write hook to process the incoming data, repeatedly for as
|
||||||
|
* long as 1) the request is not yet fully completed, and 2) the write
|
||||||
|
* hook processes at least some of the given data.
|
||||||
|
*/
|
||||||
|
for (off = 0; off < bytes; ) {
|
||||||
|
chunk = bytes - off;
|
||||||
|
if (chunk > bufsize)
|
||||||
|
chunk = bufsize;
|
||||||
|
|
||||||
|
/* Copy the data from user space. */
|
||||||
|
r = fsdriver_copyin(data, off, buf, chunk);
|
||||||
|
|
||||||
|
/* Call the write hook for the chunk. */
|
||||||
|
if (r == OK)
|
||||||
|
r = vtreefs_hooks->write_hook(node, buf, chunk, pos,
|
||||||
|
get_inode_cbdata(node));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If an error occurred, but we already processed some input,
|
||||||
|
* return a partial result. Otherwise return the error.
|
||||||
|
*/
|
||||||
|
if (r < 0)
|
||||||
|
return (off > 0) ? off : r;
|
||||||
|
|
||||||
|
off += r;
|
||||||
|
pos += r;
|
||||||
|
|
||||||
|
if ((size_t)r == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Truncate a file.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
fs_trunc(ino_t ino_nr, off_t start_pos, off_t end_pos)
|
||||||
|
{
|
||||||
|
struct inode *node;
|
||||||
|
|
||||||
|
if ((node = find_inode(ino_nr)) == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (!S_ISREG(node->i_stat.mode))
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (is_inode_deleted(node) || vtreefs_hooks->trunc_hook == NULL)
|
||||||
|
return EACCES;
|
||||||
|
|
||||||
|
/* TODO: translate this case into all-zeroes write callbacks. */
|
||||||
|
if (end_pos != 0)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
return vtreefs_hooks->trunc_hook(node, start_pos,
|
||||||
|
get_inode_cbdata(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve directory entries.
|
||||||
|
*/
|
||||||
|
ssize_t
|
||||||
|
fs_getdents(ino_t ino_nr, struct fsdriver_data * data, size_t bytes,
|
||||||
|
off_t * posp)
|
||||||
|
{
|
||||||
|
struct fsdriver_dentry fsdentry;
|
||||||
|
struct inode *node, *child;
|
||||||
|
const char *name;
|
||||||
|
off_t pos;
|
||||||
|
int r, skip, get_next, indexed;
|
||||||
|
|
||||||
|
if (*posp >= ULONG_MAX)
|
||||||
|
return EIO;
|
||||||
|
|
||||||
|
if ((node = find_inode(ino_nr)) == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
indexed = node->i_indexed;
|
||||||
|
get_next = FALSE;
|
||||||
|
child = NULL;
|
||||||
|
|
||||||
|
/* Call the getdents hook, if any, to "refresh" the directory. */
|
||||||
|
if (!is_inode_deleted(node) && vtreefs_hooks->getdents_hook != NULL) {
|
||||||
|
r = vtreefs_hooks->getdents_hook(node, get_inode_cbdata(node));
|
||||||
|
if (r != OK)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(buf != NULL);
|
||||||
|
assert(bufsize > 0);
|
||||||
|
|
||||||
|
fsdriver_dentry_init(&fsdentry, data, bytes, buf, bufsize);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* Determine which inode and name to use for this entry. */
|
||||||
|
pos = (*posp)++;
|
||||||
|
|
||||||
|
if (pos == 0) {
|
||||||
|
/* The "." entry. */
|
||||||
|
child = node;
|
||||||
|
name = ".";
|
||||||
|
} else if (pos == 1) {
|
||||||
|
/* The ".." entry. */
|
||||||
|
child = get_parent_inode(node);
|
||||||
|
if (child == NULL)
|
||||||
|
child = node;
|
||||||
|
name = "..";
|
||||||
|
} else if (pos - 2 < indexed) {
|
||||||
|
/* All indexed entries. */
|
||||||
|
child = get_inode_by_index(node, pos - 2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is no inode with this particular index,
|
||||||
|
* continue with the next index number.
|
||||||
|
*/
|
||||||
|
if (child == NULL) continue;
|
||||||
|
|
||||||
|
name = child->i_name;
|
||||||
|
} else {
|
||||||
|
/* All non-indexed entries. */
|
||||||
|
/*
|
||||||
|
* If this is the first loop iteration, first get to
|
||||||
|
* the non-indexed child identified by the current
|
||||||
|
* position.
|
||||||
|
*/
|
||||||
|
if (get_next == FALSE) {
|
||||||
|
skip = pos - indexed - 2;
|
||||||
|
child = get_first_inode(node);
|
||||||
|
|
||||||
|
/* Skip indexed children. */
|
||||||
|
while (child != NULL &&
|
||||||
|
child->i_index != NO_INDEX)
|
||||||
|
child = get_next_inode(child);
|
||||||
|
|
||||||
|
/* Skip to the right position. */
|
||||||
|
while (child != NULL && skip-- > 0)
|
||||||
|
child = get_next_inode(child);
|
||||||
|
|
||||||
|
get_next = TRUE;
|
||||||
|
} else
|
||||||
|
child = get_next_inode(child);
|
||||||
|
|
||||||
|
/* No more children? Then stop. */
|
||||||
|
if (child == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
assert(!is_inode_deleted(child));
|
||||||
|
|
||||||
|
name = child->i_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the directory entry to the output. */
|
||||||
|
r = fsdriver_dentry_add(&fsdentry,
|
||||||
|
(ino_t)get_inode_number(child), name, strlen(name),
|
||||||
|
IFTODT(child->i_stat.mode));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
} while (r > 0);
|
||||||
|
|
||||||
|
return fsdriver_dentry_finish(&fsdentry);
|
||||||
|
}
|
|
@ -26,7 +26,7 @@ static LIST_HEAD(index_head, inode) *parent_index_head;
|
||||||
/*
|
/*
|
||||||
* Initialize the inode-related state.
|
* Initialize the inode-related state.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
init_inodes(unsigned int inodes, struct inode_stat * stat,
|
init_inodes(unsigned int inodes, struct inode_stat * stat,
|
||||||
index_t nr_indexed_entries)
|
index_t nr_indexed_entries)
|
||||||
{
|
{
|
||||||
|
@ -39,13 +39,21 @@ init_inodes(unsigned int inodes, struct inode_stat * stat,
|
||||||
nr_inodes = inodes;
|
nr_inodes = inodes;
|
||||||
|
|
||||||
/* Allocate the inode and hash tables. */
|
/* Allocate the inode and hash tables. */
|
||||||
inode = malloc(nr_inodes * sizeof(inode[0]));
|
if ((inode = malloc(nr_inodes * sizeof(inode[0]))) == NULL)
|
||||||
parent_name_head = malloc(nr_inodes * sizeof(parent_name_head[0]));
|
return ENOMEM;
|
||||||
parent_index_head = malloc(nr_inodes * sizeof(parent_index_head[0]));
|
|
||||||
|
|
||||||
assert(inode != NULL);
|
parent_name_head = malloc(nr_inodes * sizeof(parent_name_head[0]));
|
||||||
assert(parent_name_head != NULL);
|
if (parent_name_head == NULL) {
|
||||||
assert(parent_index_head != NULL);
|
free(inode);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent_index_head = malloc(nr_inodes * sizeof(parent_index_head[0]));
|
||||||
|
if (parent_index_head == NULL) {
|
||||||
|
free(parent_name_head);
|
||||||
|
free(inode);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
printf("VTREEFS: allocated %d+%d+%d bytes\n",
|
printf("VTREEFS: allocated %d+%d+%d bytes\n",
|
||||||
|
@ -83,6 +91,8 @@ init_inodes(unsigned int inodes, struct inode_stat * stat,
|
||||||
set_inode_stat(node, stat);
|
set_inode_stat(node, stat);
|
||||||
node->i_indexed = nr_indexed_entries;
|
node->i_indexed = nr_indexed_entries;
|
||||||
node->i_cbdata = NULL;
|
node->i_cbdata = NULL;
|
||||||
|
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/* VTreeFS - link.c - support for symbolic links */
|
/* VTreeFS - link.c - support for symbolic links and device nodes */
|
||||||
|
|
||||||
#include "inc.h"
|
#include "inc.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Retrieve symbolic link target.
|
* Retrieve a symbolic link target.
|
||||||
*/
|
*/
|
||||||
ssize_t
|
ssize_t
|
||||||
fs_rdlink(ino_t ino_nr, struct fsdriver_data * data, size_t bytes)
|
fs_rdlink(ino_t ino_nr, struct fsdriver_data * data, size_t bytes)
|
||||||
|
@ -16,11 +16,10 @@ fs_rdlink(ino_t ino_nr, struct fsdriver_data * data, size_t bytes)
|
||||||
if ((node = find_inode(ino_nr)) == NULL)
|
if ((node = find_inode(ino_nr)) == NULL)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
/*
|
/* The hook should be provided for any FS that adds symlink inodes.. */
|
||||||
* Call the rdlink hook. The hook must be non-NULL if the file system
|
if (vtreefs_hooks->rdlink_hook == NULL)
|
||||||
* adds symlink nodes. If it doesn't, we will never get here.
|
return ENOSYS;
|
||||||
*/
|
|
||||||
assert(vtreefs_hooks->rdlink_hook != NULL);
|
|
||||||
assert(!is_inode_deleted(node)); /* symlinks cannot be opened */
|
assert(!is_inode_deleted(node)); /* symlinks cannot be opened */
|
||||||
|
|
||||||
r = vtreefs_hooks->rdlink_hook(node, path, sizeof(path),
|
r = vtreefs_hooks->rdlink_hook(node, path, sizeof(path),
|
||||||
|
@ -39,3 +38,92 @@ fs_rdlink(ino_t ino_nr, struct fsdriver_data * data, size_t bytes)
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a symbolic link.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
fs_slink(ino_t dir_nr, char * name, uid_t uid, gid_t gid,
|
||||||
|
struct fsdriver_data * data, size_t bytes)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX];
|
||||||
|
struct inode *node;
|
||||||
|
struct inode_stat stat;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((node = find_inode(dir_nr)) == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (vtreefs_hooks->slink_hook == NULL)
|
||||||
|
return ENOSYS;
|
||||||
|
|
||||||
|
if (get_inode_by_name(node, name) != NULL)
|
||||||
|
return EEXIST;
|
||||||
|
|
||||||
|
if (bytes >= sizeof(path))
|
||||||
|
return ENAMETOOLONG;
|
||||||
|
|
||||||
|
if ((r = fsdriver_copyin(data, 0, path, bytes)) != OK)
|
||||||
|
return r;
|
||||||
|
path[bytes] = 0;
|
||||||
|
|
||||||
|
memset(&stat, 0, sizeof(stat));
|
||||||
|
stat.mode = S_IFLNK | RWX_MODES;
|
||||||
|
stat.uid = uid;
|
||||||
|
stat.gid = gid;
|
||||||
|
stat.size = strlen(path);
|
||||||
|
stat.dev = 0;
|
||||||
|
|
||||||
|
return vtreefs_hooks->slink_hook(node, name, &stat, path,
|
||||||
|
get_inode_cbdata(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a device node.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
fs_mknod(ino_t dir_nr, char * name, mode_t mode, uid_t uid, gid_t gid,
|
||||||
|
dev_t rdev)
|
||||||
|
{
|
||||||
|
struct inode *node;
|
||||||
|
struct inode_stat stat;
|
||||||
|
|
||||||
|
if ((node = find_inode(dir_nr)) == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (get_inode_by_name(node, name) != NULL)
|
||||||
|
return EEXIST;
|
||||||
|
|
||||||
|
if (vtreefs_hooks->mknod_hook == NULL)
|
||||||
|
return ENOSYS;
|
||||||
|
|
||||||
|
memset(&stat, 0, sizeof(stat));
|
||||||
|
stat.mode = mode;
|
||||||
|
stat.uid = uid;
|
||||||
|
stat.gid = gid;
|
||||||
|
stat.size = 0;
|
||||||
|
stat.dev = rdev;
|
||||||
|
|
||||||
|
return vtreefs_hooks->mknod_hook(node, name, &stat,
|
||||||
|
get_inode_cbdata(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unlink a node.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
fs_unlink(ino_t dir_nr, char * name, int __unused call)
|
||||||
|
{
|
||||||
|
struct inode *dir_node, *node;
|
||||||
|
|
||||||
|
if ((dir_node = find_inode(dir_nr)) == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if ((node = get_inode_by_name(dir_node, name)) == NULL)
|
||||||
|
return ENOENT;
|
||||||
|
|
||||||
|
if (vtreefs_hooks->unlink_hook == NULL)
|
||||||
|
return ENOSYS;
|
||||||
|
|
||||||
|
return vtreefs_hooks->unlink_hook(node, get_inode_cbdata(node));
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
#ifndef _VTREEFS_PROTO_H
|
#ifndef _VTREEFS_PROTO_H
|
||||||
#define _VTREEFS_PROTO_H
|
#define _VTREEFS_PROTO_H
|
||||||
|
|
||||||
|
/* file.c */
|
||||||
|
int init_buf(size_t size);
|
||||||
|
void cleanup_buf(void);
|
||||||
|
ssize_t fs_read(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
|
||||||
|
off_t pos, int call);
|
||||||
|
ssize_t fs_write(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
|
||||||
|
off_t pos, int call);
|
||||||
|
int fs_trunc(ino_t ino_nr, off_t start_pos, off_t end_pos);
|
||||||
|
ssize_t fs_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
|
||||||
|
off_t *pos);
|
||||||
|
|
||||||
/* inode.c */
|
/* inode.c */
|
||||||
void init_inodes(unsigned int inodes, struct inode_stat *stat, index_t
|
int init_inodes(unsigned int inodes, struct inode_stat *stat,
|
||||||
nr_indexed_entries);
|
index_t nr_indexed_entries);
|
||||||
void cleanup_inodes(void);
|
void cleanup_inodes(void);
|
||||||
struct inode *find_inode(ino_t num);
|
struct inode *find_inode(ino_t num);
|
||||||
struct inode *get_inode(ino_t num);
|
struct inode *get_inode(ino_t num);
|
||||||
|
@ -15,6 +26,11 @@ int fs_putnode(ino_t ino_nr, unsigned int count);
|
||||||
|
|
||||||
/* link.c */
|
/* link.c */
|
||||||
ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes);
|
ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes);
|
||||||
|
int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
|
||||||
|
struct fsdriver_data *data, size_t bytes);
|
||||||
|
int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
|
||||||
|
dev_t rdev);
|
||||||
|
int fs_unlink(ino_t dir_nr, char *name, int call);
|
||||||
|
|
||||||
/* mount.c */
|
/* mount.c */
|
||||||
int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
|
int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
|
||||||
|
@ -28,17 +44,13 @@ void fs_other(const message *m_ptr, int ipc_status);
|
||||||
int fs_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
|
int fs_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
|
||||||
int *is_mountpt);
|
int *is_mountpt);
|
||||||
|
|
||||||
/* read.c */
|
|
||||||
ssize_t fs_read(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
|
|
||||||
off_t pos, int call);
|
|
||||||
ssize_t fs_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
|
|
||||||
off_t *pos);
|
|
||||||
|
|
||||||
/* sdbm.c */
|
/* sdbm.c */
|
||||||
long sdbm_hash(const char *str, int len);
|
long sdbm_hash(const char *str, int len);
|
||||||
|
|
||||||
/* stadir.c */
|
/* stadir.c */
|
||||||
int fs_stat(ino_t ino_nr, struct stat *buf);
|
int fs_stat(ino_t ino_nr, struct stat *buf);
|
||||||
|
int fs_chmod(ino_t ino_nr, mode_t *mode);
|
||||||
|
int fs_chown(ino_t ino_nr, uid_t uid, gid_t gid, mode_t *mode);
|
||||||
int fs_statvfs(struct statvfs *buf);
|
int fs_statvfs(struct statvfs *buf);
|
||||||
|
|
||||||
#endif /* _VTREEFS_PROTO_H */
|
#endif /* _VTREEFS_PROTO_H */
|
||||||
|
|
|
@ -1,153 +0,0 @@
|
||||||
/* VTreeFS - read.c - reading from files and directories */
|
|
||||||
|
|
||||||
#include "inc.h"
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
#define GETDENTS_BUFSIZ 4096
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read from a file.
|
|
||||||
*/
|
|
||||||
ssize_t
|
|
||||||
fs_read(ino_t ino_nr, struct fsdriver_data * data, size_t bytes,
|
|
||||||
off_t pos, int __unused call)
|
|
||||||
{
|
|
||||||
struct inode *node;
|
|
||||||
size_t len;
|
|
||||||
char *ptr;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
/* Try to get inode by its inode number. */
|
|
||||||
if ((node = find_inode(ino_nr)) == NULL)
|
|
||||||
return EINVAL;
|
|
||||||
|
|
||||||
/* Check whether the node is a regular file. */
|
|
||||||
if (!S_ISREG(node->i_stat.mode))
|
|
||||||
return EINVAL;
|
|
||||||
|
|
||||||
/* Call the read hook, if any. */
|
|
||||||
if (!is_inode_deleted(node) && vtreefs_hooks->read_hook != NULL) {
|
|
||||||
len = bytes;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* On success, the read hook provides us with a pointer to the
|
|
||||||
* resulting data. This avoids copying overhead.
|
|
||||||
*/
|
|
||||||
r = vtreefs_hooks->read_hook(node, pos, &ptr, &len,
|
|
||||||
get_inode_cbdata(node));
|
|
||||||
|
|
||||||
assert(len <= bytes);
|
|
||||||
|
|
||||||
/* Copy the resulting data to user space. */
|
|
||||||
if (r == OK && len > 0)
|
|
||||||
r = fsdriver_copyout(data, 0, ptr, len);
|
|
||||||
} else {
|
|
||||||
/* Feign an empty file. */
|
|
||||||
r = OK;
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (r != OK) ? r : len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Retrieve directory entries.
|
|
||||||
*/
|
|
||||||
ssize_t
|
|
||||||
fs_getdents(ino_t ino_nr, struct fsdriver_data * data, size_t bytes,
|
|
||||||
off_t * posp)
|
|
||||||
{
|
|
||||||
struct fsdriver_dentry fsdentry;
|
|
||||||
struct inode *node, *child;
|
|
||||||
const char *name;
|
|
||||||
off_t pos;
|
|
||||||
int r, skip, get_next, indexed;
|
|
||||||
static char buf[GETDENTS_BUFSIZ];
|
|
||||||
|
|
||||||
if (*posp >= ULONG_MAX)
|
|
||||||
return EIO;
|
|
||||||
|
|
||||||
if ((node = find_inode(ino_nr)) == NULL)
|
|
||||||
return EINVAL;
|
|
||||||
|
|
||||||
indexed = node->i_indexed;
|
|
||||||
get_next = FALSE;
|
|
||||||
child = NULL;
|
|
||||||
|
|
||||||
/* Call the getdents hook, if any, to "refresh" the directory. */
|
|
||||||
if (!is_inode_deleted(node) && vtreefs_hooks->getdents_hook != NULL) {
|
|
||||||
r = vtreefs_hooks->getdents_hook(node, get_inode_cbdata(node));
|
|
||||||
if (r != OK)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
fsdriver_dentry_init(&fsdentry, data, bytes, buf, sizeof(buf));
|
|
||||||
|
|
||||||
do {
|
|
||||||
/* Determine which inode and name to use for this entry. */
|
|
||||||
pos = (*posp)++;
|
|
||||||
|
|
||||||
if (pos == 0) {
|
|
||||||
/* The "." entry. */
|
|
||||||
child = node;
|
|
||||||
name = ".";
|
|
||||||
} else if (pos == 1) {
|
|
||||||
/* The ".." entry. */
|
|
||||||
child = get_parent_inode(node);
|
|
||||||
if (child == NULL)
|
|
||||||
child = node;
|
|
||||||
name = "..";
|
|
||||||
} else if (pos - 2 < indexed) {
|
|
||||||
/* All indexed entries. */
|
|
||||||
child = get_inode_by_index(node, pos - 2);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there is no inode with this particular index,
|
|
||||||
* continue with the next index number.
|
|
||||||
*/
|
|
||||||
if (child == NULL) continue;
|
|
||||||
|
|
||||||
name = child->i_name;
|
|
||||||
} else {
|
|
||||||
/* All non-indexed entries. */
|
|
||||||
/*
|
|
||||||
* If this is the first loop iteration, first get to
|
|
||||||
* the non-indexed child identified by the current
|
|
||||||
* position.
|
|
||||||
*/
|
|
||||||
if (get_next == FALSE) {
|
|
||||||
skip = pos - indexed - 2;
|
|
||||||
child = get_first_inode(node);
|
|
||||||
|
|
||||||
/* Skip indexed children. */
|
|
||||||
while (child != NULL &&
|
|
||||||
child->i_index != NO_INDEX)
|
|
||||||
child = get_next_inode(child);
|
|
||||||
|
|
||||||
/* Skip to the right position. */
|
|
||||||
while (child != NULL && skip-- > 0)
|
|
||||||
child = get_next_inode(child);
|
|
||||||
|
|
||||||
get_next = TRUE;
|
|
||||||
} else
|
|
||||||
child = get_next_inode(child);
|
|
||||||
|
|
||||||
/* No more children? Then stop. */
|
|
||||||
if (child == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
assert(!is_inode_deleted(child));
|
|
||||||
|
|
||||||
name = child->i_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the directory entry to the output. */
|
|
||||||
r = fsdriver_dentry_add(&fsdentry,
|
|
||||||
(ino_t)get_inode_number(child), name, strlen(name),
|
|
||||||
IFTODT(child->i_stat.mode));
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
} while (r > 0);
|
|
||||||
|
|
||||||
return fsdriver_dentry_finish(&fsdentry);
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* VTreeFS - stadir.c - file and file system status retrieval */
|
/* VTreeFS - stadir.c - file and file system status management */
|
||||||
|
|
||||||
#include "inc.h"
|
#include "inc.h"
|
||||||
|
|
||||||
|
@ -44,6 +44,72 @@ fs_stat(ino_t ino_nr, struct stat * buf)
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change file mode.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
fs_chmod(ino_t ino_nr, mode_t * mode)
|
||||||
|
{
|
||||||
|
struct inode *node;
|
||||||
|
struct inode_stat stat;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((node = find_inode(ino_nr)) == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (vtreefs_hooks->chstat_hook == NULL)
|
||||||
|
return ENOSYS;
|
||||||
|
|
||||||
|
get_inode_stat(node, &stat);
|
||||||
|
|
||||||
|
stat.mode = (stat.mode & ~ALL_MODES) | (*mode & ALL_MODES);
|
||||||
|
|
||||||
|
r = vtreefs_hooks->chstat_hook(node, &stat, get_inode_cbdata(node));
|
||||||
|
|
||||||
|
if (r != OK)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
get_inode_stat(node, &stat);
|
||||||
|
|
||||||
|
*mode = stat.mode;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change file ownership.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
fs_chown(ino_t ino_nr, uid_t uid, gid_t gid, mode_t * mode)
|
||||||
|
{
|
||||||
|
struct inode *node;
|
||||||
|
struct inode_stat stat;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((node = find_inode(ino_nr)) == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (vtreefs_hooks->chstat_hook == NULL)
|
||||||
|
return ENOSYS;
|
||||||
|
|
||||||
|
get_inode_stat(node, &stat);
|
||||||
|
|
||||||
|
stat.uid = uid;
|
||||||
|
stat.gid = gid;
|
||||||
|
stat.mode &= ~(S_ISUID | S_ISGID);
|
||||||
|
|
||||||
|
r = vtreefs_hooks->chstat_hook(node, &stat, get_inode_cbdata(node));
|
||||||
|
|
||||||
|
if (r != OK)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
get_inode_stat(node, &stat);
|
||||||
|
|
||||||
|
*mode = stat.mode;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Retrieve file system statistics.
|
* Retrieve file system statistics.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -9,9 +9,16 @@ struct fsdriver vtreefs_table = {
|
||||||
.fdr_lookup = fs_lookup,
|
.fdr_lookup = fs_lookup,
|
||||||
.fdr_putnode = fs_putnode,
|
.fdr_putnode = fs_putnode,
|
||||||
.fdr_read = fs_read,
|
.fdr_read = fs_read,
|
||||||
|
.fdr_write = fs_write,
|
||||||
.fdr_getdents = fs_getdents,
|
.fdr_getdents = fs_getdents,
|
||||||
|
.fdr_trunc = fs_trunc,
|
||||||
|
.fdr_mknod = fs_mknod,
|
||||||
|
.fdr_unlink = fs_unlink,
|
||||||
|
.fdr_slink = fs_slink,
|
||||||
.fdr_rdlink = fs_rdlink,
|
.fdr_rdlink = fs_rdlink,
|
||||||
.fdr_stat = fs_stat,
|
.fdr_stat = fs_stat,
|
||||||
|
.fdr_chmod = fs_chmod,
|
||||||
|
.fdr_chown = fs_chown,
|
||||||
.fdr_statvfs = fs_statvfs,
|
.fdr_statvfs = fs_statvfs,
|
||||||
.fdr_other = fs_other
|
.fdr_other = fs_other
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,16 +5,24 @@
|
||||||
static unsigned int inodes;
|
static unsigned int inodes;
|
||||||
static struct inode_stat *root_stat;
|
static struct inode_stat *root_stat;
|
||||||
static index_t root_entries;
|
static index_t root_entries;
|
||||||
|
static size_t buf_size;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize internal state, and register with VFS.
|
* Initialize internal state. This is the only place where dynamic memory
|
||||||
|
* allocation takes place.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
init_server(int __unused type, sef_init_info_t * __unused info)
|
init_server(int __unused type, sef_init_info_t * __unused info)
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
/* Initialize the virtual tree. */
|
/* Initialize the virtual tree. */
|
||||||
init_inodes(inodes, root_stat, root_entries);
|
if ((r = init_inodes(inodes, root_stat, root_entries)) != OK)
|
||||||
|
panic("init_inodes failed: %d", r);
|
||||||
|
|
||||||
|
/* Initialize the I/O buffer. */
|
||||||
|
if ((r = init_buf(buf_size)) != OK)
|
||||||
|
panic("init_buf failed: %d", r);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +62,7 @@ sef_local_startup(void)
|
||||||
* Call the message hook, if there is one.
|
* Call the message hook, if there is one.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
fs_other(const message * m_ptr, int __unused ipc_status)
|
fs_other(const message * m_ptr, int ipc_status)
|
||||||
{
|
{
|
||||||
message msg;
|
message msg;
|
||||||
|
|
||||||
|
@ -65,7 +73,7 @@ fs_other(const message * m_ptr, int __unused ipc_status)
|
||||||
*/
|
*/
|
||||||
msg = *m_ptr;
|
msg = *m_ptr;
|
||||||
|
|
||||||
vtreefs_hooks->message_hook(&msg);
|
vtreefs_hooks->message_hook(&msg, ipc_status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +84,7 @@ fs_other(const message * m_ptr, int __unused ipc_status)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
start_vtreefs(struct fs_hooks * hooks, unsigned int nr_inodes,
|
start_vtreefs(struct fs_hooks * hooks, unsigned int nr_inodes,
|
||||||
struct inode_stat * stat, index_t nr_indexed_entries)
|
struct inode_stat * stat, index_t nr_indexed_entries, size_t bufsize)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -87,10 +95,12 @@ start_vtreefs(struct fs_hooks * hooks, unsigned int nr_inodes,
|
||||||
inodes = nr_inodes;
|
inodes = nr_inodes;
|
||||||
root_stat = stat;
|
root_stat = stat;
|
||||||
root_entries = nr_indexed_entries;
|
root_entries = nr_indexed_entries;
|
||||||
|
buf_size = bufsize;
|
||||||
|
|
||||||
sef_local_startup();
|
sef_local_startup();
|
||||||
|
|
||||||
fsdriver_task(&vtreefs_table);
|
fsdriver_task(&vtreefs_table);
|
||||||
|
|
||||||
|
cleanup_buf();
|
||||||
cleanup_inodes();
|
cleanup_inodes();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,62 +1,29 @@
|
||||||
/* buf.c - by Alen Stojanov and David van Moolenbroek, taken from procfs */
|
/* buf.c - by Alen Stojanov and David van Moolenbroek, taken from procfs */
|
||||||
#define _SYSTEM 1 /* tell headers that this is the kernel */
|
|
||||||
#define DEVMAN_SERVER 1
|
|
||||||
|
|
||||||
#include <minix/config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <lib.h>
|
|
||||||
#include <minix/timers.h>
|
|
||||||
|
|
||||||
#include <minix/callnr.h>
|
|
||||||
#include <minix/type.h>
|
|
||||||
#include <minix/const.h>
|
|
||||||
#include <minix/com.h>
|
|
||||||
#include <minix/syslib.h>
|
|
||||||
#include <minix/sysutil.h>
|
|
||||||
#include <minix/vfsif.h>
|
|
||||||
#include <minix/endpoint.h>
|
|
||||||
#include <minix/sysinfo.h>
|
|
||||||
#include <minix/u64.h>
|
|
||||||
#include <minix/sysinfo.h>
|
|
||||||
#include <minix/type.h>
|
|
||||||
#include <minix/ipc.h>
|
|
||||||
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/times.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include <minix/vtreefs.h>
|
|
||||||
|
|
||||||
#include <minix/devman.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "devman.h"
|
||||||
|
#include "proto.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
|
||||||
#define BUF_SIZE 4096
|
|
||||||
|
|
||||||
static char buf[BUF_SIZE + 1];
|
static char *buf;
|
||||||
static size_t off, left, used;
|
static size_t left, used;
|
||||||
static off_t skip;
|
static off_t skip;
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* buf_init *
|
* buf_init *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void buf_init(off_t start, size_t len)
|
void buf_init(char *ptr, size_t len, off_t start)
|
||||||
{
|
{
|
||||||
/* Initialize the buffer for fresh use. The first 'start' bytes of the
|
/* Initialize the buffer for fresh use. The output is to be stored into
|
||||||
* produced output are to be skipped. After that, up to a total of
|
* 'ptr' which is BUF_SIZE bytes in size, since that is the size we
|
||||||
* 'len' bytes are requested.
|
* requested. Due to the way vsnprintf works, we cannot use the last
|
||||||
|
* byte of this buffer. The first 'start' bytes of the produced output
|
||||||
|
* are to be skipped. After that, a total of 'len' bytes are requested.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
buf = ptr;
|
||||||
skip = start;
|
skip = start;
|
||||||
left = MIN(len, BUF_SIZE);
|
left = MIN(len, BUF_SIZE - 1);
|
||||||
off = 0;
|
|
||||||
used = 0;
|
used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,21 +42,23 @@ void buf_printf(char *fmt, ...)
|
||||||
|
|
||||||
/* There is no way to estimate how much space the result will take, so
|
/* There is no way to estimate how much space the result will take, so
|
||||||
* we need to produce the string even when skipping part of the start.
|
* we need to produce the string even when skipping part of the start.
|
||||||
* If part of the result is to be skipped, do not memcpy; instead, save
|
|
||||||
* the offset of where the result starts within the buffer.
|
|
||||||
*
|
|
||||||
* The null terminating character is not part of the result, so room
|
* The null terminating character is not part of the result, so room
|
||||||
* must be given for it to be stored after completely filling up the
|
* must be given for it to be stored after completely filling up the
|
||||||
* requested part of the buffer.
|
* requested part of the buffer.
|
||||||
*/
|
*/
|
||||||
max = MIN(skip + left, BUF_SIZE);
|
max = MIN(skip + left + 1, BUF_SIZE);
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
len = vsnprintf(&buf[off + used], max + 1, fmt, args);
|
len = vsnprintf(&buf[used], max, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
|
/* The snprintf family returns the number of bytes that would be stored
|
||||||
|
* if the buffer were large enough, excluding the null terminator.
|
||||||
|
*/
|
||||||
|
if (len >= BUF_SIZE)
|
||||||
|
len = BUF_SIZE - 1;
|
||||||
|
|
||||||
if (skip > 0) {
|
if (skip > 0) {
|
||||||
assert(off == 0);
|
|
||||||
assert(used == 0);
|
assert(used == 0);
|
||||||
|
|
||||||
if (skip >= len) {
|
if (skip >= len) {
|
||||||
|
@ -98,16 +67,15 @@ void buf_printf(char *fmt, ...)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
off = skip;
|
memmove(buf, &buf[skip], len - skip);
|
||||||
if (left > BUF_SIZE - off)
|
|
||||||
left = BUF_SIZE - off;
|
len -= skip;
|
||||||
len -= off;
|
|
||||||
skip = 0;
|
skip = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(skip == 0);
|
assert(skip == 0);
|
||||||
assert(len >= 0);
|
assert(len >= 0);
|
||||||
assert((long) left >= 0);
|
assert((ssize_t) left >= 0);
|
||||||
|
|
||||||
if (len > (ssize_t) left)
|
if (len > (ssize_t) left)
|
||||||
len = left;
|
len = left;
|
||||||
|
@ -142,22 +110,20 @@ void buf_append(char *data, size_t len)
|
||||||
if (len > left)
|
if (len > left)
|
||||||
len = left;
|
len = left;
|
||||||
|
|
||||||
memcpy(&buf[off + used], data, len);
|
memcpy(&buf[used], data, len);
|
||||||
|
|
||||||
used += len;
|
used += len;
|
||||||
left -= len;
|
left -= len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* buf_get *
|
* buf_result *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
size_t buf_get(char **ptr)
|
ssize_t buf_result(void)
|
||||||
{
|
{
|
||||||
/* Return the buffer's starting address and the length of the used
|
/* Return the resulting number of bytes produced, not counting the
|
||||||
* part, not counting the trailing null character for the latter.
|
* trailing null character in the buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
*ptr = &buf[off];
|
|
||||||
|
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ static struct devman_device *_find_dev(struct devman_device *dev, int
|
||||||
dev_id);
|
dev_id);
|
||||||
static int devman_dev_add_info(struct devman_device *dev, struct
|
static int devman_dev_add_info(struct devman_device *dev, struct
|
||||||
devman_device_info_entry *entry, char *buf);
|
devman_device_info_entry *entry, char *buf);
|
||||||
static int devman_event_read(char **ptr, size_t *len,off_t offset, void
|
static ssize_t devman_event_read(char *ptr, size_t len, off_t offset, void
|
||||||
*data);
|
*data);
|
||||||
|
|
||||||
static int devman_del_device(struct devman_device *dev);
|
static int devman_del_device(struct devman_device *dev);
|
||||||
|
@ -138,11 +138,12 @@ devman_device_remove_event(struct devman_device* dev)
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* devman_event_read *
|
* devman_event_read *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static int
|
static ssize_t
|
||||||
devman_event_read(char **ptr, size_t *len,off_t offset, void *data)
|
devman_event_read(char *ptr, size_t len, off_t offset, void *data)
|
||||||
{
|
{
|
||||||
struct devman_event *ev = NULL;
|
struct devman_event *ev = NULL;
|
||||||
struct devman_event_inode *n;
|
struct devman_event_inode *n;
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
n = (struct devman_event_inode *) data;
|
n = (struct devman_event_inode *) data;
|
||||||
|
|
||||||
|
@ -150,35 +151,34 @@ devman_event_read(char **ptr, size_t *len,off_t offset, void *data)
|
||||||
ev = TAILQ_LAST(&n->event_queue, event_head);
|
ev = TAILQ_LAST(&n->event_queue, event_head);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf_init(offset, *len);
|
buf_init(ptr, len, offset);
|
||||||
if (ev != NULL)
|
if (ev != NULL)
|
||||||
buf_printf("%s", ev->data);
|
buf_printf("%s", ev->data);
|
||||||
|
|
||||||
*len = buf_get(ptr);
|
r = buf_result();
|
||||||
|
|
||||||
/* read all (EOF)? */
|
/* read all (EOF)? */
|
||||||
if (ev != NULL && *len == 0) {
|
if (ev != NULL && r == 0) {
|
||||||
TAILQ_REMOVE(&n->event_queue, ev, events);
|
TAILQ_REMOVE(&n->event_queue, ev, events);
|
||||||
free(ev);
|
free(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* devman_static_info_read *
|
* devman_static_info_read *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static int
|
static ssize_t
|
||||||
devman_static_info_read(char **ptr, size_t *len, off_t offset, void *data)
|
devman_static_info_read(char *ptr, size_t len, off_t offset, void *data)
|
||||||
{
|
{
|
||||||
struct devman_static_info_inode *n;
|
struct devman_static_info_inode *n;
|
||||||
|
|
||||||
n = (struct devman_static_info_inode *) data;
|
n = (struct devman_static_info_inode *) data;
|
||||||
|
|
||||||
buf_init(offset, *len);
|
buf_init(ptr, len, offset);
|
||||||
buf_printf("%s\n", n->data);
|
buf_printf("%s\n", n->data);
|
||||||
*len = buf_get(ptr);
|
return buf_result();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
#include <minix/devman.h>
|
#include <minix/devman.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#define BUF_SIZE 4097
|
||||||
|
|
||||||
#define DEVMAN_DEFAULT_MODE (S_IRUSR | S_IRGRP | S_IROTH)
|
#define DEVMAN_DEFAULT_MODE (S_IRUSR | S_IRGRP | S_IROTH)
|
||||||
#define DEVMAN_STRING_LEN 128
|
#define DEVMAN_STRING_LEN 128
|
||||||
|
|
||||||
|
@ -48,8 +50,8 @@ enum devman_inode_type {
|
||||||
DEVMAN_DEVICE
|
DEVMAN_DEVICE
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*devman_read_fn)
|
typedef ssize_t (*devman_read_fn)
|
||||||
(char **ptr, size_t *len, off_t offset, void *data);
|
(char *ptr, size_t len, off_t offset, void *data);
|
||||||
|
|
||||||
struct devman_device_file {
|
struct devman_device_file {
|
||||||
int minor;
|
int minor;
|
||||||
|
|
|
@ -43,24 +43,23 @@ static void init_hook(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int message_hook (message *m)
|
static void message_hook(message *m, int __unused ipc_status)
|
||||||
{
|
{
|
||||||
switch (m->m_type) {
|
switch (m->m_type) {
|
||||||
case DEVMAN_ADD_DEV:
|
case DEVMAN_ADD_DEV:
|
||||||
return do_add_device(m);
|
do_add_device(m);
|
||||||
case DEVMAN_DEL_DEV:
|
case DEVMAN_DEL_DEV:
|
||||||
return do_del_device(m);
|
do_del_device(m);
|
||||||
case DEVMAN_BIND:
|
case DEVMAN_BIND:
|
||||||
return do_bind_device(m);
|
do_bind_device(m);
|
||||||
case DEVMAN_UNBIND:
|
case DEVMAN_UNBIND:
|
||||||
return do_unbind_device(m);
|
do_unbind_device(m);
|
||||||
default: return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static ssize_t
|
||||||
read_hook
|
read_hook
|
||||||
(struct inode *inode, off_t offset, char **ptr, size_t *len, cbdata_t cbdata)
|
(struct inode *inode, char *ptr, size_t len, off_t offset, cbdata_t cbdata)
|
||||||
{
|
{
|
||||||
struct devman_inode *d_inode = (struct devman_inode *) cbdata;
|
struct devman_inode *d_inode = (struct devman_inode *) cbdata;
|
||||||
|
|
||||||
|
@ -77,7 +76,7 @@ int main (int argc, char* argv[])
|
||||||
/* fill in the hooks */
|
/* fill in the hooks */
|
||||||
memset(&hooks, 0, sizeof(hooks));
|
memset(&hooks, 0, sizeof(hooks));
|
||||||
hooks.init_hook = init_hook;
|
hooks.init_hook = init_hook;
|
||||||
hooks.read_hook = read_hook; /* read will never be called */
|
hooks.read_hook = read_hook;
|
||||||
hooks.message_hook = message_hook; /* handle the ds_update call */
|
hooks.message_hook = message_hook; /* handle the ds_update call */
|
||||||
|
|
||||||
root_stat.mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH;
|
root_stat.mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH;
|
||||||
|
@ -87,7 +86,7 @@ int main (int argc, char* argv[])
|
||||||
root_stat.dev = NO_DEV;
|
root_stat.dev = NO_DEV;
|
||||||
|
|
||||||
/* limit the number of indexed entries */
|
/* limit the number of indexed entries */
|
||||||
start_vtreefs(&hooks, 1024 , &root_stat, 0);
|
start_vtreefs(&hooks, 1024, &root_stat, 0, BUF_SIZE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
#define _DEVMAN_PROTO_H
|
#define _DEVMAN_PROTO_H
|
||||||
|
|
||||||
/* buf.c */
|
/* buf.c */
|
||||||
void buf_init(off_t start, size_t len);
|
void buf_init(char *ptr, size_t len, off_t off);
|
||||||
void buf_printf(char *fmt, ...);
|
void buf_printf(char *fmt, ...);
|
||||||
void buf_append(char *data, size_t len);
|
void buf_append(char *data, size_t len);
|
||||||
size_t buf_get(char **ptr);
|
ssize_t buf_result(void);
|
||||||
|
|
||||||
/* message handlers */
|
/* message handlers */
|
||||||
int do_add_device(message *m);
|
int do_add_device(message *m);
|
||||||
|
|
Loading…
Reference in a new issue