HelenOS sources
This source file includes following definitions.
- plb_insert_entry
- plb_clear_entry
- vfs_link_internal
- out_lookup
- _vfs_lookup_internal
- vfs_lookup_internal
#include "vfs.h"
#include <macros.h>
#include <async.h>
#include <errno.h>
#include <str.h>
#include <stdarg.h>
#include <stdbool.h>
#include <fibril_synch.h>
#include <adt/list.h>
#include <vfs/canonify.h>
#include <dirent.h>
#include <assert.h>
FIBRIL_MUTEX_INITIALIZE(plb_mutex);
LIST_INITIALIZE(plb_entries);
uint8_t *plb = NULL;
static errno_t plb_insert_entry(plb_entry_t *entry, char *path, size_t *start,
size_t len)
{
fibril_mutex_lock(&plb_mutex);
link_initialize(&entry->plb_link);
entry->len = len;
size_t first;
size_t last;
if (list_empty(&plb_entries)) {
first = 0;
last = PLB_SIZE - 1;
} else {
plb_entry_t *oldest = list_get_instance(
list_first(&plb_entries), plb_entry_t, plb_link);
plb_entry_t *newest = list_get_instance(
list_last(&plb_entries), plb_entry_t, plb_link);
first = (newest->index + newest->len) % PLB_SIZE;
last = (oldest->index - 1) % PLB_SIZE;
}
if (first <= last) {
if ((last - first) + 1 < len) {
fibril_mutex_unlock(&plb_mutex);
return ELIMIT;
}
} else {
if (PLB_SIZE - ((first - last) + 1) < len) {
fibril_mutex_unlock(&plb_mutex);
return ELIMIT;
}
}
entry->index = first;
entry->len = len;
list_append(&entry->plb_link, &plb_entries);
fibril_mutex_unlock(&plb_mutex);
size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
size_t cnt2 = len - cnt1;
memcpy(&plb[first], path, cnt1);
memcpy(plb, &path[cnt1], cnt2);
*start = first;
return EOK;
}
static void plb_clear_entry(plb_entry_t *entry, size_t first, size_t len)
{
fibril_mutex_lock(&plb_mutex);
list_remove(&entry->plb_link);
size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
size_t cnt2 = len - cnt1;
memset(&plb[first], 0, cnt1);
memset(plb, 0, cnt2);
fibril_mutex_unlock(&plb_mutex);
}
errno_t vfs_link_internal(vfs_node_t *base, char *path, vfs_triplet_t *child)
{
assert(base != NULL);
assert(child != NULL);
assert(base->fs_handle);
assert(child->fs_handle);
assert(path != NULL);
vfs_lookup_res_t res;
char component[NAME_MAX + 1];
errno_t rc;
size_t len;
char *npath = canonify(path, &len);
if (!npath) {
rc = EINVAL;
goto out;
}
path = npath;
vfs_triplet_t *triplet;
char *slash = str_rchr(path, L'/');
if (slash && slash != path) {
if (slash[1] == 0) {
rc = EINVAL;
goto out;
}
memcpy(component, slash + 1, str_size(slash));
*slash = 0;
rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res);
if (rc != EOK)
goto out;
triplet = &res.triplet;
*slash = '/';
} else {
if (base->mount != NULL) {
rc = EINVAL;
goto out;
}
memcpy(component, path + 1, str_size(path));
triplet = (vfs_triplet_t *) base;
}
if (triplet->fs_handle != child->fs_handle ||
triplet->service_id != child->service_id) {
rc = EXDEV;
goto out;
}
async_exch_t *exch = vfs_exchange_grab(triplet->fs_handle);
aid_t req = async_send_3(exch, VFS_OUT_LINK, triplet->service_id,
triplet->index, child->index, NULL);
rc = async_data_write_start(exch, component, str_size(component) + 1);
errno_t orig_rc;
async_wait_for(req, &orig_rc);
vfs_exchange_release(exch);
if (orig_rc != EOK)
rc = orig_rc;
out:
return rc;
}
static errno_t out_lookup(vfs_triplet_t *base, size_t *pfirst, size_t *plen,
int lflag, vfs_lookup_res_t *result)
{
assert(base);
assert(result);
errno_t rc;
ipc_call_t answer;
async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) *pfirst,
(sysarg_t) *plen, (sysarg_t) base->service_id,
(sysarg_t) base->index, (sysarg_t) lflag, &answer);
async_wait_for(req, &rc);
vfs_exchange_release(exch);
if (rc != EOK)
return rc;
unsigned last = *pfirst + *plen;
*pfirst = ipc_get_arg3(&answer) & 0xffff;
*plen = last - *pfirst;
result->triplet.fs_handle = (fs_handle_t) ipc_get_arg1(&answer);
result->triplet.service_id = base->service_id;
result->triplet.index = (fs_index_t) ipc_get_arg2(&answer);
result->size = MERGE_LOUP32(ipc_get_arg4(&answer), ipc_get_arg5(&answer));
result->type = (ipc_get_arg3(&answer) >> 16) ?
VFS_NODE_DIRECTORY : VFS_NODE_FILE;
return EOK;
}
static errno_t _vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
vfs_lookup_res_t *result, size_t len)
{
size_t first;
errno_t rc;
plb_entry_t entry;
rc = plb_insert_entry(&entry, path, &first, len);
if (rc != EOK)
return rc;
size_t next = first;
size_t nlen = len;
vfs_lookup_res_t res;
while (nlen > 0) {
while (base->mount) {
if (lflag & L_DISABLE_MOUNTS) {
rc = EXDEV;
goto out;
}
base = base->mount;
}
rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag,
&res);
if (rc != EOK)
goto out;
if (nlen > 0) {
base = vfs_node_peek(&res);
if (!base) {
rc = ENOENT;
goto out;
}
if (!base->mount) {
vfs_node_put(base);
rc = ENOENT;
goto out;
}
vfs_node_put(base);
if (lflag & L_DISABLE_MOUNTS) {
rc = EXDEV;
goto out;
}
}
}
assert(nlen == 0);
rc = EOK;
if (result != NULL) {
if (!(lflag & (L_MP | L_DISABLE_MOUNTS))) {
base = vfs_node_peek(&res);
if (base && base->mount) {
while (base->mount) {
vfs_node_addref(base->mount);
vfs_node_t *nbase = base->mount;
vfs_node_put(base);
base = nbase;
}
result->triplet = *((vfs_triplet_t *) base);
result->type = base->type;
result->size = base->size;
vfs_node_put(base);
goto out;
}
if (base)
vfs_node_put(base);
}
*result = res;
}
out:
plb_clear_entry(&entry, first, len);
return rc;
}
errno_t vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
vfs_lookup_res_t *result)
{
assert(base != NULL);
assert(path != NULL);
size_t len;
errno_t rc;
char *npath = canonify(path, &len);
if (!npath) {
rc = EINVAL;
return rc;
}
path = npath;
assert(path[0] == '/');
if (lflag & (L_CREATE | L_UNLINK)) {
char *slash = str_rchr(path, L'/');
vfs_node_t *parent = base;
if (slash != path) {
int tflag = lflag;
vfs_lookup_res_t tres;
tflag &= ~(L_CREATE | L_EXCLUSIVE | L_UNLINK | L_FILE);
tflag |= L_DIRECTORY;
rc = _vfs_lookup_internal(base, path, tflag, &tres,
slash - path);
if (rc != EOK)
return rc;
parent = vfs_node_get(&tres);
if (!parent)
return ENOMEM;
} else
vfs_node_addref(parent);
rc = _vfs_lookup_internal(parent, slash, lflag, result,
len - (slash - path));
vfs_node_put(parent);
} else {
rc = _vfs_lookup_internal(base, path, lflag, result, len);
}
return rc;
}
HelenOS homepage, sources at GitHub