path_to_vnode() should now be able to resolve symbolic links (not tested

yet) - up to 16 symlinks are allowed in one path (following BeOS' restriction).


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@518 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2002-07-28 19:39:49 +00:00
parent 5e949b7dfc
commit 847248db20
1 changed files with 79 additions and 41 deletions

View File

@ -53,6 +53,8 @@
#endif
#include <fs_info.h>
#define MAX_SYM_LINKS 16
// Passed in buffers from user-space shouldn't be in the kernel
#define CHECK_USER_ADDRESS(x) \
((addr)(x) < KERNEL_BASE || (addr)(x) > KERNEL_TOP)
@ -560,30 +562,14 @@ entry_ref_to_vnode(fs_id fsID,vnode_id directoryID,const char *name,struct vnode
static int
path_to_vnode(char *path, struct vnode **_vnode, bool kernel)
vnode_path_to_vnode(struct vnode *vnode, char *path, struct vnode **_vnode, int count)
{
struct vnode *vnode;
int err = 0;
int status = 0;
if (!path)
return EINVAL;
// figure out if we need to start at root or at cwd
if (*path == '/') {
while (*++path == '/')
;
vnode = root_vnode;
inc_vnode_ref_count(vnode);
} else {
struct io_context *context = get_current_io_context(kernel);
mutex_lock(&context->io_mutex);
vnode = context->cwd;
inc_vnode_ref_count(vnode);
mutex_unlock(&context->io_mutex);
}
for (;;) {
while (true) {
struct vnode *nextVnode;
vnode_id vnodeID;
char *nextPath;
@ -592,10 +578,8 @@ path_to_vnode(char *path, struct vnode **_vnode, bool kernel)
PRINT(("path_to_vnode: top of loop. p = %p, *p = %c, p = '%s'\n", path, *path, path));
// done?
if (*path == '\0') {
err = 0;
if (*path == '\0')
break;
}
// walk to find the next path component ("path" will point to a single
// path component), and filter out multiple slashes
@ -620,30 +604,24 @@ path_to_vnode(char *path, struct vnode **_vnode, bool kernel)
}
// tell the filesystem to get the vnode of this path component
err = FS_CALL(vnode,fs_lookup)(vnode->mount->cookie, vnode->private_node, path, &vnodeID, &type);
if (err < 0) {
status = FS_CALL(vnode,fs_lookup)(vnode->mount->cookie, vnode->private_node, path, &vnodeID, &type);
if (status < 0) {
put_vnode(vnode);
goto out;
return status;
}
if (S_ISLNK(type)) {
// ToDo: we have to resolve the link here
nextVnode = NULL;
} else {
// lookup the vnode, the call to fs_lookup should have caused a get_vnode to be called
// from inside the filesystem, thus the vnode would have to be in the list and it's
// ref count incremented at this point
mutex_lock(&vfs_vnode_mutex);
nextVnode = lookup_vnode(vnode->fs_id, vnodeID);
mutex_unlock(&vfs_vnode_mutex);
}
// lookup the vnode, the call to fs_lookup should have caused a get_vnode to be called
// from inside the filesystem, thus the vnode would have to be in the list and it's
// ref count incremented at this point
mutex_lock(&vfs_vnode_mutex);
nextVnode = lookup_vnode(vnode->fs_id, vnodeID);
mutex_unlock(&vfs_vnode_mutex);
if (!nextVnode) {
// pretty screwed up here
panic("path_to_vnode: could not lookup vnode (fsid 0x%x vnid 0x%Lx)\n", vnode->fs_id, vnodeID);
err = ERR_VFS_PATH_NOT_FOUND;
put_vnode(vnode);
goto out;
return ERR_VFS_PATH_NOT_FOUND;
}
// decrease the ref count on the old dir we just looked up into
@ -652,6 +630,39 @@ path_to_vnode(char *path, struct vnode **_vnode, bool kernel)
path = nextPath;
vnode = nextVnode;
// If the new node is a symbolic link, resolve it
if (S_ISLNK(type)) {
char *buffer;
if (count + 1 > MAX_SYM_LINKS) {
put_vnode(vnode);
return B_LINK_LIMIT;
}
buffer = kmalloc(SYS_MAX_PATH_LEN);
if (buffer == NULL) {
put_vnode(vnode);
return B_NO_MEMORY;
}
status = FS_CALL(vnode,fs_read_link)(vnode->mount->cookie, vnode->private_node, buffer, SYS_MAX_PATH_LEN);
if (status < B_OK) {
put_vnode(vnode);
kfree(buffer);
return status;
}
status = vnode_path_to_vnode(vnode, buffer, &nextVnode, count + 1);
put_vnode(vnode);
kfree(buffer);
if (status < B_OK)
return status;
vnode = nextVnode;
}
// see if we hit a mount point
if (vnode->covered_by) {
nextVnode = vnode->covered_by;
@ -662,9 +673,36 @@ path_to_vnode(char *path, struct vnode **_vnode, bool kernel)
}
*_vnode = vnode;
return B_OK;
}
out:
return err;
static int
path_to_vnode(char *path, struct vnode **_vnode, bool kernel)
{
struct vnode *start;
int linkCount = 0;
int status = 0;
if (!path)
return EINVAL;
// figure out if we need to start at root or at cwd
if (*path == '/') {
while (*++path == '/')
;
start = root_vnode;
inc_vnode_ref_count(start);
} else {
struct io_context *context = get_current_io_context(kernel);
mutex_lock(&context->io_mutex);
start = context->cwd;
inc_vnode_ref_count(start);
mutex_unlock(&context->io_mutex);
}
return vnode_path_to_vnode(start, path, _vnode, 0);
}
@ -1756,7 +1794,7 @@ dir_create_entry_ref(fs_id fsID, vnode_id parentID, const char *name, int perms,
vnode_id newID;
int status;
FUNCTION(("dir_create_entry_ref(dev = %ld, ino = %Ld, name = '%s', perms = %d)\n", fdID, parentID, name, perms));
FUNCTION(("dir_create_entry_ref(dev = %d, ino = %Ld, name = '%s', perms = %d)\n", fsID, parentID, name, perms));
status = get_vnode(fsID, parentID, &vnode, kernel);
if (status < B_OK)