* Changed get_vnode_name() to take a dirent* parameter instead of the
name (saves copying the name, if that has to be done anyway) and added a wrapper version with the old interface. * dir_vnode_to_path() was broken for file systems that didn't support the get_vnode_name() hook. It resolved the mount point too early, so that it was searching the mount point and not the FS root dir for the node. It uses the get_vnode_name() function now (before resolving the mount point). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20305 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1784,14 +1784,19 @@ fd_and_path_to_dir_vnode(int fd, char *path, struct vnode **_vnode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns a vnode's name in the d_name field of a supplied dirent buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
get_vnode_name(struct vnode *vnode, struct vnode *parent,
|
get_vnode_name(struct vnode *vnode, struct vnode *parent, struct dirent *buffer,
|
||||||
char *name, size_t nameSize)
|
size_t bufferSize)
|
||||||
{
|
{
|
||||||
VNodePutter vnodePutter;
|
if (bufferSize < sizeof(struct dirent))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
// See if vnode is the root of a mount and move to the covered
|
// See if vnode is the root of a mount and move to the covered
|
||||||
// vnode so we get the underlying file system
|
// vnode so we get the underlying file system
|
||||||
|
VNodePutter vnodePutter;
|
||||||
if (vnode->mount->root_vnode == vnode && vnode->mount->covers_vnode != NULL) {
|
if (vnode->mount->root_vnode == vnode && vnode->mount->covers_vnode != NULL) {
|
||||||
vnode = vnode->mount->covers_vnode;
|
vnode = vnode->mount->covers_vnode;
|
||||||
inc_vnode_ref_count(vnode);
|
inc_vnode_ref_count(vnode);
|
||||||
@@ -1801,7 +1806,8 @@ get_vnode_name(struct vnode *vnode, struct vnode *parent,
|
|||||||
if (FS_CALL(vnode, get_vnode_name)) {
|
if (FS_CALL(vnode, get_vnode_name)) {
|
||||||
// The FS supports getting the name of a vnode.
|
// The FS supports getting the name of a vnode.
|
||||||
return FS_CALL(vnode, get_vnode_name)(vnode->mount->cookie,
|
return FS_CALL(vnode, get_vnode_name)(vnode->mount->cookie,
|
||||||
vnode->private_node, name, nameSize);
|
vnode->private_node, buffer->d_name,
|
||||||
|
(char*)buffer + bufferSize - buffer->d_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The FS doesn't support getting the name of a vnode. So we search the
|
// The FS doesn't support getting the name of a vnode. So we search the
|
||||||
@@ -1815,18 +1821,14 @@ get_vnode_name(struct vnode *vnode, struct vnode *parent,
|
|||||||
status_t status = FS_CALL(parent, open_dir)(parent->mount->cookie,
|
status_t status = FS_CALL(parent, open_dir)(parent->mount->cookie,
|
||||||
parent->private_node, &cookie);
|
parent->private_node, &cookie);
|
||||||
if (status >= B_OK) {
|
if (status >= B_OK) {
|
||||||
char buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
|
|
||||||
struct dirent *dirent = (struct dirent *)buffer;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
uint32 num = 1;
|
uint32 num = 1;
|
||||||
status = dir_read(parent, cookie, dirent, sizeof(buffer), &num);
|
status = dir_read(parent, cookie, buffer, bufferSize, &num);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (vnode->id == dirent->d_ino) {
|
if (vnode->id == buffer->d_ino) {
|
||||||
// found correct entry!
|
// found correct entry!
|
||||||
if (strlcpy(name, dirent->d_name, nameSize) >= nameSize)
|
|
||||||
status = B_BUFFER_OVERFLOW;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1836,6 +1838,24 @@ get_vnode_name(struct vnode *vnode, struct vnode *parent,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
get_vnode_name(struct vnode *vnode, struct vnode *parent, char *name,
|
||||||
|
size_t nameSize)
|
||||||
|
{
|
||||||
|
char buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
|
||||||
|
struct dirent *dirent = (struct dirent *)buffer;
|
||||||
|
|
||||||
|
status_t status = get_vnode_name(vnode, parent, buffer, sizeof(buffer));
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (strlcpy(name, dirent->d_name, nameSize) >= nameSize)
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Gets the full path to a given directory vnode.
|
/** Gets the full path to a given directory vnode.
|
||||||
* It uses the fs_get_vnode_name() call to get the name of a vnode; if a
|
* It uses the fs_get_vnode_name() call to get the name of a vnode; if a
|
||||||
* file system doesn't support this call, it will fall back to iterating
|
* file system doesn't support this call, it will fall back to iterating
|
||||||
@@ -1889,7 +1909,7 @@ dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
|||||||
char nameBuffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
|
char nameBuffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
|
||||||
char *name = &((struct dirent *)nameBuffer)->d_name[0];
|
char *name = &((struct dirent *)nameBuffer)->d_name[0];
|
||||||
struct vnode *parentVnode;
|
struct vnode *parentVnode;
|
||||||
vnode_id parentID, id;
|
vnode_id parentID;
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
// lookup the parent vnode
|
// lookup the parent vnode
|
||||||
@@ -1909,6 +1929,10 @@ dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the node's name
|
||||||
|
status = get_vnode_name(vnode, parentVnode, (struct dirent*)nameBuffer,
|
||||||
|
sizeof(nameBuffer));
|
||||||
|
|
||||||
// resolve a volume root to its mount point
|
// resolve a volume root to its mount point
|
||||||
mountPoint = resolve_volume_root_to_mount_point(parentVnode);
|
mountPoint = resolve_volume_root_to_mount_point(parentVnode);
|
||||||
if (mountPoint) {
|
if (mountPoint) {
|
||||||
@@ -1919,17 +1943,6 @@ dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
|||||||
|
|
||||||
bool hitRoot = (parentVnode == vnode);
|
bool hitRoot = (parentVnode == vnode);
|
||||||
|
|
||||||
// Does the file system support getting the name of a vnode?
|
|
||||||
// If so, get it here...
|
|
||||||
if (status == B_OK && FS_CALL(vnode, get_vnode_name)) {
|
|
||||||
status = FS_CALL(vnode, get_vnode_name)(vnode->mount->cookie, vnode->private_node,
|
|
||||||
name, B_FILE_NAME_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... if not, find it out later (by iterating through
|
|
||||||
// the parent directory, searching for the id)
|
|
||||||
id = vnode->id;
|
|
||||||
|
|
||||||
// release the current vnode, we only need its parent from now on
|
// release the current vnode, we only need its parent from now on
|
||||||
put_vnode(vnode);
|
put_vnode(vnode);
|
||||||
vnode = parentVnode;
|
vnode = parentVnode;
|
||||||
@@ -1937,6 +1950,12 @@ dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (hitRoot) {
|
||||||
|
// we have reached "/", which means we have constructed the full
|
||||||
|
// path
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// ToDo: add an explicit check for loops in about 10 levels to do
|
// ToDo: add an explicit check for loops in about 10 levels to do
|
||||||
// real loop detection
|
// real loop detection
|
||||||
|
|
||||||
@@ -1946,41 +1965,7 @@ dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hitRoot) {
|
// add the name in front of the current path
|
||||||
// we have reached "/", which means we have constructed the full
|
|
||||||
// path
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!FS_CALL(vnode, get_vnode_name)) {
|
|
||||||
// If we haven't got the vnode's name yet, we have to search for it
|
|
||||||
// in the parent directory now
|
|
||||||
fs_cookie cookie;
|
|
||||||
|
|
||||||
status = FS_CALL(vnode, open_dir)(vnode->mount->cookie, vnode->private_node,
|
|
||||||
&cookie);
|
|
||||||
if (status >= B_OK) {
|
|
||||||
struct dirent *dirent = (struct dirent *)nameBuffer;
|
|
||||||
while (true) {
|
|
||||||
uint32 num = 1;
|
|
||||||
status = dir_read(vnode, cookie, dirent, sizeof(nameBuffer),
|
|
||||||
&num);
|
|
||||||
|
|
||||||
if (status < B_OK)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (id == dirent->d_ino)
|
|
||||||
// found correct entry!
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status < B_OK)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the name infront of the current path
|
|
||||||
name[B_FILE_NAME_LENGTH - 1] = '\0';
|
name[B_FILE_NAME_LENGTH - 1] = '\0';
|
||||||
length = strlen(name);
|
length = strlen(name);
|
||||||
insert -= length;
|
insert -= length;
|
||||||
@@ -6915,14 +6900,15 @@ _user_open_parent_dir(int fd, char *userName, size_t nameLength)
|
|||||||
return B_FILE_ERROR;
|
return B_FILE_ERROR;
|
||||||
|
|
||||||
// get the vnode name
|
// get the vnode name
|
||||||
char name[B_FILE_NAME_LENGTH];
|
char _buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
|
||||||
status_t status = get_vnode_name(dirVNode, parentVNode,
|
struct dirent *buffer = (struct dirent*)_buffer;
|
||||||
name, sizeof(name));
|
status_t status = get_vnode_name(dirVNode, parentVNode, buffer,
|
||||||
|
sizeof(_buffer));
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
// copy the name to the userland buffer
|
// copy the name to the userland buffer
|
||||||
int len = user_strlcpy(userName, name, nameLength);
|
int len = user_strlcpy(userName, buffer->d_name, nameLength);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
return len;
|
return len;
|
||||||
if (len >= (int)nameLength)
|
if (len >= (int)nameLength)
|
||||||
|
|||||||
Reference in New Issue
Block a user