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); uint8 event, selectsync *sync);
status_t (*fsync)(fs_volume fs, fs_vnode v); 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 (*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); 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_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_create_dir(int fd, const char *path, int perms);
extern status_t _kern_remove_dir(const char *path); extern status_t _kern_remove_dir(const char *path);
extern ssize_t _kern_read_link(int fd, const char *path, char *buffer, extern status_t _kern_read_link(int fd, const char *path, char *buffer,
size_t bufferSize); size_t *_bufferSize);
extern status_t _kern_write_link(const char *path, const char *toPath); extern status_t _kern_write_link(const char *path, const char *toPath);
extern status_t _kern_create_symlink(int fd, const char *path, extern status_t _kern_create_symlink(int fd, const char *path,
const char *toPath, int mode); 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_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_create_dir(int fd, const char *path, int perms);
status_t _user_remove_dir(const char *path); 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_write_link(const char *path, const char *toPath);
status_t _user_create_symlink(int fd, const char *path, const char *toPath, status_t _user_create_symlink(int fd, const char *path, const char *toPath,
int mode); int mode);
@@ -1269,29 +1269,33 @@ bfs_access(void *_ns, void *_node, int accessMode)
static status_t 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(); FUNCTION();
Inode *inode = (Inode *)_node; Inode *inode = (Inode *)_node;
size_t bufferSize = *_bufferSize;
if (!inode->IsSymLink()) if (!inode->IsSymLink())
RETURN_ERROR(B_BAD_VALUE); RETURN_ERROR(B_BAD_VALUE);
if (inode->Flags() & INODE_LONG_SYMLINK) { if (inode->Flags() & INODE_LONG_SYMLINK) {
// we also need space for the terminating null byte // we also need space for the terminating null byte
if (inode->Size() >= bufferSize) if (inode->Size() >= bufferSize) {
*_bufferSize = inode->Size();
return B_BUFFER_OVERFLOW; 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) if (status < B_OK)
RETURN_ERROR(status); RETURN_ERROR(status);
buffer[bufferSize] = '\0'; buffer[*_bufferSize] = '\0';
return B_OK; 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_BUFFER_OVERFLOW;
return B_OK; return B_OK;
+5 -3
View File
@@ -1115,15 +1115,17 @@ devfs_fsync(fs_volume _fs, fs_vnode _v)
static status_t 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; struct devfs_vnode *link = (struct devfs_vnode *)_link;
if (!S_ISLNK(link->stream.type)) if (!S_ISLNK(link->stream.type))
return B_BAD_VALUE; return B_BAD_VALUE;
if (bufferSize <= link->stream.u.symlink.length) if (*_bufferSize <= link->stream.u.symlink.length) {
return B_NAME_TOO_LONG; *_bufferSize = link->stream.u.symlink.length + 1;
return B_BUFFER_OVERFLOW;
}
memcpy(buffer, link->stream.u.symlink.path, link->stream.u.symlink.length + 1); memcpy(buffer, link->stream.u.symlink.path, link->stream.u.symlink.length + 1);
return B_OK; return B_OK;
+13 -10
View File
@@ -1,11 +1,12 @@
/* /*
** Copyright 2002-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the Haiku License. * Distributed under the terms of the MIT License.
** *
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License. * Distributed under the terms of the NewOS License.
*/ */
#include <KernelExport.h> #include <KernelExport.h>
#include <vfs.h> #include <vfs.h>
#include <debug.h> #include <debug.h>
@@ -768,27 +769,29 @@ rootfs_can_page(fs_volume _fs, fs_vnode _v, fs_cookie cookie)
static status_t 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) 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 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) 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 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; struct rootfs_vnode *link = _link;
if (!S_ISLNK(link->stream.type)) if (!S_ISLNK(link->stream.type))
return B_BAD_VALUE; return B_BAD_VALUE;
if (bufferSize <= link->stream.symlink.length) if (*_bufferSize <= link->stream.symlink.length) {
return B_NAME_TOO_LONG; *_bufferSize = link->stream.symlink.length + 1;
return B_BUFFER_OVERFLOW;
}
memcpy(buffer, link->stream.symlink.path, link->stream.symlink.length + 1); memcpy(buffer, link->stream.symlink.path, link->stream.symlink.length + 1);
return B_OK; 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 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')) { if (S_ISLNK(type) && !(!traverseLeafLink && nextPath[0] == '\0')) {
size_t bufferSize;
char *buffer; char *buffer;
PRINT(("traverse link\n")); PRINT(("traverse link\n"));
@@ -1368,13 +1369,14 @@ vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
goto resolve_link_error; goto resolve_link_error;
} }
buffer = (char *)malloc(B_PATH_NAME_LENGTH); buffer = (char *)malloc(bufferSize = B_PATH_NAME_LENGTH);
if (buffer == NULL) { if (buffer == NULL) {
status = B_NO_MEMORY; status = B_NO_MEMORY;
goto resolve_link_error; 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) { if (status < B_OK) {
free(buffer); free(buffer);
@@ -3573,7 +3575,7 @@ common_unlock_node(int fd, bool kernel)
static status_t 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) bool kernel)
{ {
struct vnode *vnode; struct vnode *vnode;
@@ -3583,9 +3585,10 @@ common_read_link(int fd, char *path, char *buffer, size_t bufferSize,
if (status < B_OK) if (status < B_OK)
return status; return status;
if (FS_CALL(vnode, read_link) != NULL) if (FS_CALL(vnode, read_link) != NULL) {
status = FS_CALL(vnode, read_link)(vnode->mount->cookie, vnode->private_node, buffer, bufferSize); status = FS_CALL(vnode, read_link)(vnode->mount->cookie,
else vnode->private_node, buffer, _bufferSize);
} else
status = B_BAD_VALUE; status = B_BAD_VALUE;
put_vnode(vnode); 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 * 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 * ignored; a relative path is reckoned off of the directory (!) identified
* by \a fd. * 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 fd The FD. May be < 0.
* \param path The absolute or relative path. May be \c NULL. * \param path The absolute or relative path. May be \c NULL.
* \param buffer The buffer into which the contents of the symlink shall be * \param buffer The buffer into which the contents of the symlink shall be
* written. * 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 * \return The length of the link on success or an appropriate error code
*/ */
ssize_t status_t
_kern_read_link(int fd, const char *path, char *buffer, size_t bufferSize) _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
{ {
status_t status; 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]; char pathBuffer[B_PATH_NAME_LENGTH + 1];
strlcpy(pathBuffer, path, B_PATH_NAME_LENGTH); strlcpy(pathBuffer, path, B_PATH_NAME_LENGTH);
status = common_read_link(fd, pathBuffer, buffer, bufferSize, true); return common_read_link(fd, pathBuffer, buffer, _bufferSize, true);
} else }
status = common_read_link(fd, NULL, buffer, bufferSize, true);
if (status < B_OK) return common_read_link(fd, NULL, buffer, _bufferSize, true);
return status;
// Unlike what POSIX wants, our file systems must always null terminate links
return strlen(buffer);
} }
@@ -6083,14 +6083,16 @@ _user_remove_dir(const char *userPath)
} }
ssize_t status_t
_user_read_link(int fd, const char *userPath, char *userBuffer, size_t bufferSize) _user_read_link(int fd, const char *userPath, char *userBuffer, size_t *userBufferSize)
{ {
char path[B_PATH_NAME_LENGTH + 1]; char path[B_PATH_NAME_LENGTH + 1];
char buffer[B_PATH_NAME_LENGTH]; char buffer[B_PATH_NAME_LENGTH];
size_t bufferSize;
int status; 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; return B_BAD_ADDRESS;
if (userPath) { 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) if (bufferSize > B_PATH_NAME_LENGTH)
bufferSize = B_PATH_NAME_LENGTH; bufferSize = B_PATH_NAME_LENGTH;
}
status = common_read_link(fd, path, buffer, bufferSize, false); status = common_read_link(fd, userPath ? path : NULL, buffer, &bufferSize, false);
} else
status = common_read_link(fd, 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) if (status < B_OK)
return status; return status;
status = user_strlcpy(userBuffer, buffer, bufferSize); if (user_strlcpy(userBuffer, buffer, bufferSize) < 0)
if (status < 0) return B_BAD_ADDRESS;
return status;
return (status >= (int)bufferSize ? bufferSize : status + 1); 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. * Distributed under the terms of the MIT License.
*/ */
@@ -20,9 +20,13 @@
ssize_t ssize_t
readlink(const char *path, char *buffer, size_t bufferSize) 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 // This software is part of the Haiku distribution and is covered
// by the OpenBeOS license. // by the MIT license.
//--------------------------------------------------------------------- //---------------------------------------------------------------------
/*! /*!
\file Entry.cpp \file Entry.cpp
@@ -925,10 +925,10 @@ BEntry::set(int dirFD, const char *path, bool traverse)
// we need to traverse the symlink // we need to traverse the symlink
if (--linkLimit < 0) if (--linkLimit < 0)
return B_LINK_LIMIT; return B_LINK_LIMIT;
ssize_t readBytes = _kern_read_link(dirFD, leafName, tmpPath, size_t bufferSize = B_PATH_NAME_LENGTH;
B_PATH_NAME_LENGTH); error = _kern_read_link(dirFD, leafName, tmpPath, &bufferSize);
if (readBytes < 0) if (error < 0)
return readBytes; return error;
path = tmpPath; path = tmpPath;
// next round... // next round...
} }
+8 -6
View File
@@ -529,14 +529,16 @@ _kern_rewind_dir(int fd)
// _kern_read_link // _kern_read_link
extern "C" extern "C"
ssize_t status_t
_kern_read_link(int fd, const char *path, char *buffer, size_t bufferSize) _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
{ {
ssize_t result = _kreadlink_(fd, path, buffer, bufferSize); ssize_t result = _kreadlink_(fd, path, buffer, *_bufferSize);
if (result >= 0) if (result < 0)
buffer[result] = '\0';
return result; return result;
buffer[result] = '\0';
*_bufferSize = result;
return B_OK;
} }
// _kern_unlink // _kern_unlink
+10 -5
View File
@@ -1,6 +1,6 @@
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered // This software is part of the Haiku distribution and is covered
// by the OpenBeOS license. // by the MIT license.
//--------------------------------------------------------------------- //---------------------------------------------------------------------
/*! /*!
\file SymLink.cpp \file SymLink.cpp
@@ -103,13 +103,18 @@ BSymLink::~BSymLink()
- some other error code - some other error code
*/ */
ssize_t ssize_t
BSymLink::ReadLink(char *buf, size_t size) BSymLink::ReadLink(char *buffer, size_t size)
{ {
if (!buf) if (!buffer)
return B_BAD_VALUE; return B_BAD_VALUE;
if (InitCheck() != B_OK) if (InitCheck() != B_OK)
return B_FILE_ERROR; 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 // MakeLinkedPath