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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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...
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user