Changed our read link syscall and FS interface call to make it easily possible to be POSIX compliant.

Also changed readlink() to be POSIX compliant with those changes.
"ls -l" does now resolve links properly again (the new coreutils version outlined the problems).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12263 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-04-06 16:07:10 +00:00
parent a6548f7b39
commit 219dacab3c
11 changed files with 98 additions and 72 deletions
+1 -1
View File
@@ -90,7 +90,7 @@ typedef struct file_system_info {
uint8 event, selectsync *sync);
status_t (*fsync)(fs_volume fs, fs_vnode v);
status_t (*read_link)(fs_volume fs, fs_vnode link, char *buffer, size_t bufferSize);
status_t (*read_link)(fs_volume fs, fs_vnode link, char *buffer, size_t *_bufferSize);
status_t (*write_link)(fs_volume fs, fs_vnode link, char *toPath);
status_t (*create_symlink)(fs_volume fs, fs_vnode dir, const char *name, const char *path, int mode);
+2 -2
View File
@@ -134,8 +134,8 @@ extern off_t _kern_seek(int fd, off_t pos, int seekType);
extern status_t _kern_create_dir_entry_ref(dev_t device, ino_t inode, const char *name, int perms);
extern status_t _kern_create_dir(int fd, const char *path, int perms);
extern status_t _kern_remove_dir(const char *path);
extern ssize_t _kern_read_link(int fd, const char *path, char *buffer,
size_t bufferSize);
extern status_t _kern_read_link(int fd, const char *path, char *buffer,
size_t *_bufferSize);
extern status_t _kern_write_link(const char *path, const char *toPath);
extern status_t _kern_create_symlink(int fd, const char *path,
const char *toPath, int mode);
+1 -1
View File
@@ -119,7 +119,7 @@ off_t _user_seek(int fd, off_t pos, int seekType);
status_t _user_create_dir_entry_ref(dev_t device, ino_t inode, const char *name, int perms);
status_t _user_create_dir(int fd, const char *path, int perms);
status_t _user_remove_dir(const char *path);
ssize_t _user_read_link(int fd, const char *path, char *buffer, size_t bufferSize);
status_t _user_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize);
status_t _user_write_link(const char *path, const char *toPath);
status_t _user_create_symlink(int fd, const char *path, const char *toPath,
int mode);
@@ -1269,29 +1269,33 @@ bfs_access(void *_ns, void *_node, int accessMode)
static status_t
bfs_read_link(void *_ns, void *_node, char *buffer, size_t bufferSize)
bfs_read_link(void *_ns, void *_node, char *buffer, size_t *_bufferSize)
{
FUNCTION();
Inode *inode = (Inode *)_node;
size_t bufferSize = *_bufferSize;
if (!inode->IsSymLink())
RETURN_ERROR(B_BAD_VALUE);
if (inode->Flags() & INODE_LONG_SYMLINK) {
// we also need space for the terminating null byte
if (inode->Size() >= bufferSize)
if (inode->Size() >= bufferSize) {
*_bufferSize = inode->Size();
return B_BUFFER_OVERFLOW;
}
status_t status = inode->ReadAt(0, (uint8 *)buffer, &bufferSize);
status_t status = inode->ReadAt(0, (uint8 *)buffer, _bufferSize);
if (status < B_OK)
RETURN_ERROR(status);
buffer[bufferSize] = '\0';
buffer[*_bufferSize] = '\0';
return B_OK;
}
if (strlcpy(buffer, inode->Node().short_symlink, bufferSize) > bufferSize)
*_bufferSize = strlcpy(buffer, inode->Node().short_symlink, bufferSize);
if (*_bufferSize > bufferSize)
return B_BUFFER_OVERFLOW;
return B_OK;
+5 -3
View File
@@ -1115,15 +1115,17 @@ devfs_fsync(fs_volume _fs, fs_vnode _v)
static status_t
devfs_read_link(fs_volume _fs, fs_vnode _link, char *buffer, size_t bufferSize)
devfs_read_link(fs_volume _fs, fs_vnode _link, char *buffer, size_t *_bufferSize)
{
struct devfs_vnode *link = (struct devfs_vnode *)_link;
if (!S_ISLNK(link->stream.type))
return B_BAD_VALUE;
if (bufferSize <= link->stream.u.symlink.length)
return B_NAME_TOO_LONG;
if (*_bufferSize <= link->stream.u.symlink.length) {
*_bufferSize = link->stream.u.symlink.length + 1;
return B_BUFFER_OVERFLOW;
}
memcpy(buffer, link->stream.u.symlink.path, link->stream.u.symlink.length + 1);
return B_OK;
+15 -12
View File
@@ -1,10 +1,11 @@
/*
** Copyright 2002-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the Haiku License.
**
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#include <KernelExport.h>
#include <vfs.h>
@@ -768,27 +769,29 @@ rootfs_can_page(fs_volume _fs, fs_vnode _v, fs_cookie cookie)
static status_t
rootfs_read_pages(fs_volume _fs, fs_vnode _v, fs_cookie cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
{
return EPERM;
return B_NOT_ALLOWED;
}
static status_t
rootfs_write_pages(fs_volume _fs, fs_vnode _v, fs_cookie cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
{
return EPERM;
return B_NOT_ALLOWED;
}
static status_t
rootfs_read_link(fs_volume _fs, fs_vnode _link, char *buffer, size_t bufferSize)
rootfs_read_link(fs_volume _fs, fs_vnode _link, char *buffer, size_t *_bufferSize)
{
struct rootfs_vnode *link = _link;
if (!S_ISLNK(link->stream.type))
return B_BAD_VALUE;
if (bufferSize <= link->stream.symlink.length)
return B_NAME_TOO_LONG;
if (*_bufferSize <= link->stream.symlink.length) {
*_bufferSize = link->stream.symlink.length + 1;
return B_BUFFER_OVERFLOW;
}
memcpy(buffer, link->stream.symlink.path, link->stream.symlink.length + 1);
return B_OK;
+33 -27
View File
@@ -1358,6 +1358,7 @@ vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
// If the new node is a symbolic link, resolve it (if we've been told to do it)
if (S_ISLNK(type) && !(!traverseLeafLink && nextPath[0] == '\0')) {
size_t bufferSize;
char *buffer;
PRINT(("traverse link\n"));
@@ -1368,13 +1369,14 @@ vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
goto resolve_link_error;
}
buffer = (char *)malloc(B_PATH_NAME_LENGTH);
buffer = (char *)malloc(bufferSize = B_PATH_NAME_LENGTH);
if (buffer == NULL) {
status = B_NO_MEMORY;
goto resolve_link_error;
}
status = FS_CALL(nextVnode, read_link)(nextVnode->mount->cookie, nextVnode->private_node, buffer, B_PATH_NAME_LENGTH);
status = FS_CALL(nextVnode, read_link)(nextVnode->mount->cookie,
nextVnode->private_node, buffer, &bufferSize);
if (status < B_OK) {
free(buffer);
@@ -3573,7 +3575,7 @@ common_unlock_node(int fd, bool kernel)
static status_t
common_read_link(int fd, char *path, char *buffer, size_t bufferSize,
common_read_link(int fd, char *path, char *buffer, size_t *_bufferSize,
bool kernel)
{
struct vnode *vnode;
@@ -3583,9 +3585,10 @@ common_read_link(int fd, char *path, char *buffer, size_t bufferSize,
if (status < B_OK)
return status;
if (FS_CALL(vnode, read_link) != NULL)
status = FS_CALL(vnode, read_link)(vnode->mount->cookie, vnode->private_node, buffer, bufferSize);
else
if (FS_CALL(vnode, read_link) != NULL) {
status = FS_CALL(vnode, read_link)(vnode->mount->cookie,
vnode->private_node, buffer, _bufferSize);
} else
status = B_BAD_VALUE;
put_vnode(vnode);
@@ -5261,17 +5264,19 @@ _kern_remove_dir(const char *path)
* symlink to be read. If both are given and the path is absolute, \a fd is
* ignored; a relative path is reckoned off of the directory (!) identified
* by \a fd.
* If this function fails with B_BUFFER_OVERFLOW, the \a _bufferSize pointer
* will still be updated to reflect the required buffer size.
*
* \param fd The FD. May be < 0.
* \param path The absolute or relative path. May be \c NULL.
* \param buffer The buffer into which the contents of the symlink shall be
* written.
* \param bufferSize The size of the supplied buffer.
* \param _bufferSize A pointer to the size of the supplied buffer.
* \return The length of the link on success or an appropriate error code
*/
ssize_t
_kern_read_link(int fd, const char *path, char *buffer, size_t bufferSize)
status_t
_kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
{
status_t status;
@@ -5279,15 +5284,10 @@ _kern_read_link(int fd, const char *path, char *buffer, size_t bufferSize)
char pathBuffer[B_PATH_NAME_LENGTH + 1];
strlcpy(pathBuffer, path, B_PATH_NAME_LENGTH);
status = common_read_link(fd, pathBuffer, buffer, bufferSize, true);
} else
status = common_read_link(fd, NULL, buffer, bufferSize, true);
if (status < B_OK)
return status;
return common_read_link(fd, pathBuffer, buffer, _bufferSize, true);
}
// Unlike what POSIX wants, our file systems must always null terminate links
return strlen(buffer);
return common_read_link(fd, NULL, buffer, _bufferSize, true);
}
@@ -6083,14 +6083,16 @@ _user_remove_dir(const char *userPath)
}
ssize_t
_user_read_link(int fd, const char *userPath, char *userBuffer, size_t bufferSize)
status_t
_user_read_link(int fd, const char *userPath, char *userBuffer, size_t *userBufferSize)
{
char path[B_PATH_NAME_LENGTH + 1];
char buffer[B_PATH_NAME_LENGTH];
size_t bufferSize;
int status;
if (!IS_USER_ADDRESS(userBuffer))
if (!IS_USER_ADDRESS(userBuffer) || !IS_USER_ADDRESS(userBufferSize)
|| user_memcpy(&bufferSize, userBufferSize, sizeof(size_t)) < B_OK)
return B_BAD_ADDRESS;
if (userPath) {
@@ -6103,18 +6105,22 @@ _user_read_link(int fd, const char *userPath, char *userBuffer, size_t bufferSiz
if (bufferSize > B_PATH_NAME_LENGTH)
bufferSize = B_PATH_NAME_LENGTH;
}
status = common_read_link(fd, path, buffer, bufferSize, false);
} else
status = common_read_link(fd, NULL, buffer, bufferSize, false);
status = common_read_link(fd, userPath ? path : NULL, buffer, &bufferSize, false);
// we also update the bufferSize in case of errors
// (the real length will be returned in case of B_BUFFER_OVERFLOW)
if (user_memcpy(userBufferSize, &bufferSize, sizeof(size_t)) < B_OK)
return B_BAD_ADDRESS;
if (status < B_OK)
return status;
status = user_strlcpy(userBuffer, buffer, bufferSize);
if (status < 0)
return status;
return (status >= (int)bufferSize ? bufferSize : status + 1);
if (user_strlcpy(userBuffer, buffer, bufferSize) < 0)
return B_BAD_ADDRESS;
return B_OK;
}
+7 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2004, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
@@ -20,9 +20,13 @@
ssize_t
readlink(const char *path, char *buffer, size_t bufferSize)
{
int status = _kern_read_link(-1, path, buffer, bufferSize);
status_t status = _kern_read_link(-1, path, buffer, &bufferSize);
if (status < B_OK && status != B_BUFFER_OVERFLOW) {
errno = status;
return -1;
}
RETURN_AND_SET_ERRNO(status);
return bufferSize;
}
+6 -6
View File
@@ -1,6 +1,6 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
// This software is part of the Haiku distribution and is covered
// by the MIT license.
//---------------------------------------------------------------------
/*!
\file Entry.cpp
@@ -925,10 +925,10 @@ BEntry::set(int dirFD, const char *path, bool traverse)
// we need to traverse the symlink
if (--linkLimit < 0)
return B_LINK_LIMIT;
ssize_t readBytes = _kern_read_link(dirFD, leafName, tmpPath,
B_PATH_NAME_LENGTH);
if (readBytes < 0)
return readBytes;
size_t bufferSize = B_PATH_NAME_LENGTH;
error = _kern_read_link(dirFD, leafName, tmpPath, &bufferSize);
if (error < 0)
return error;
path = tmpPath;
// next round...
}
+8 -6
View File
@@ -529,14 +529,16 @@ _kern_rewind_dir(int fd)
// _kern_read_link
extern "C"
ssize_t
_kern_read_link(int fd, const char *path, char *buffer, size_t bufferSize)
status_t
_kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
{
ssize_t result = _kreadlink_(fd, path, buffer, bufferSize);
if (result >= 0)
buffer[result] = '\0';
ssize_t result = _kreadlink_(fd, path, buffer, *_bufferSize);
if (result < 0)
return result;
return result;
buffer[result] = '\0';
*_bufferSize = result;
return B_OK;
}
// _kern_unlink
+10 -5
View File
@@ -1,6 +1,6 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
// This software is part of the Haiku distribution and is covered
// by the MIT license.
//---------------------------------------------------------------------
/*!
\file SymLink.cpp
@@ -103,13 +103,18 @@ BSymLink::~BSymLink()
- some other error code
*/
ssize_t
BSymLink::ReadLink(char *buf, size_t size)
BSymLink::ReadLink(char *buffer, size_t size)
{
if (!buf)
if (!buffer)
return B_BAD_VALUE;
if (InitCheck() != B_OK)
return B_FILE_ERROR;
return _kern_read_link(get_fd(), NULL, buf, size);
status_t error = _kern_read_link(get_fd(), NULL, buffer, &size);
if (error < B_OK)
return error;
return size;
}
// MakeLinkedPath