* Aligned the semantics of the read_symlink() FS module hook with the

readlink() function. It is no longer required to null-terminate the
  string, shall not fail, if the buffer is too small, and shall return
  the length of the string actually written into the buffer.
* Adjusted rootfs, devfs, and bfs accordingly. Also adjusted their
  read_stat() hooks to return the correct symlink length in st_size.
* Our readlink() does now comply to the standard (and BeOS).
  Additionally if the buffer is big enough it is nice to non-conforming
  apps and null-terminates it.
* BSymLink::ReadLink() explicitly null-terminates the string now.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24425 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-03-17 21:37:40 +00:00
parent 4f893e39ab
commit 1b32947d3f
9 changed files with 61 additions and 45 deletions
@@ -49,7 +49,7 @@ fill_stat_buffer(Inode *inode, struct stat &stat)
if (inode->IsSymLink() && (node.Flags() & INODE_LONG_SYMLINK) == 0) {
// symlinks report the size of the link here
stat.st_size = strlen(node.short_symlink) + 1;
stat.st_size = strlen(node.short_symlink);
} else
stat.st_size = inode->Size();
}
@@ -1366,29 +1366,26 @@ 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) {
*_bufferSize = inode->Size() + 1;
return B_BUFFER_OVERFLOW;
}
if (inode->Size() < *_bufferSize)
*_bufferSize = inode->Size();
status_t status = inode->ReadAt(0, (uint8 *)buffer, _bufferSize);
if (status < B_OK)
RETURN_ERROR(status);
buffer[++*_bufferSize] = '\0';
return B_OK;
}
*_bufferSize = strlcpy(buffer, inode->Node().short_symlink, bufferSize) + 1;
if (*_bufferSize > bufferSize)
return B_BUFFER_OVERFLOW;
size_t linkLen = strlen(inode->Node().short_symlink);
if (linkLen < *_bufferSize)
*_bufferSize = linkLen;
memcpy(buffer, inode->Node().short_symlink, *_bufferSize);
return B_OK;
}
+2 -1
View File
@@ -928,10 +928,11 @@ BEntry::set(int dirFD, const char *path, bool traverse)
// we need to traverse the symlink
if (--linkLimit < 0)
return B_LINK_LIMIT;
size_t bufferSize = B_PATH_NAME_LENGTH;
size_t bufferSize = B_PATH_NAME_LENGTH - 1;
error = _kern_read_link(dirFD, leafName, tmpPath, &bufferSize);
if (error < 0)
return error;
tmpPath[bufferSize] = '\0';
path = tmpPath;
// next round...
}
-1
View File
@@ -534,7 +534,6 @@ _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
if (result < 0)
return result;
buffer[result] = '\0';
*_bufferSize = result;
return B_OK;
}
+10 -3
View File
@@ -93,7 +93,8 @@ BSymLink::~BSymLink()
// ReadLink
//! Reads the contents of the symbolic link into a buffer.
/*! \param buf the buffer
/*! The string written to the buffer will be null-terminated.
\param buf the buffer
\param size the size of the buffer
\return
- the number of bytes written into the buffer
@@ -110,11 +111,17 @@ BSymLink::ReadLink(char *buffer, size_t size)
if (InitCheck() != B_OK)
return B_FILE_ERROR;
status_t error = _kern_read_link(get_fd(), NULL, buffer, &size);
size_t linkLen = size;
status_t error = _kern_read_link(get_fd(), NULL, buffer, &linkLen);
if (error < B_OK)
return error;
return size;
// null-terminate
if (linkLen >= size)
return B_BUFFER_OVERFLOW;
buffer[linkLen] = '\0';
return linkLen;
}
// MakeLinkedPath
+5 -6
View File
@@ -1880,13 +1880,10 @@ devfs_read_link(fs_volume _fs, fs_vnode _link, char *buffer, size_t *_bufferSize
if (!S_ISLNK(link->stream.type))
return B_BAD_VALUE;
*_bufferSize = link->stream.u.symlink.length + 1;
// we always need to return the number of bytes we intend to write!
if (link->stream.u.symlink.length < *_bufferSize)
*_bufferSize = link->stream.u.symlink.length;
if (bufferSize <= link->stream.u.symlink.length)
return B_BUFFER_OVERFLOW;
memcpy(buffer, link->stream.u.symlink.path, link->stream.u.symlink.length + 1);
memcpy(buffer, link->stream.u.symlink.path, *_bufferSize);
return B_OK;
}
@@ -2478,6 +2475,8 @@ devfs_read_stat(fs_volume _fs, fs_vnode _vnode, struct stat *stat)
// is this a real block device? then let's have it reported like that
if (stat->st_size != 0)
stat->st_mode = S_IFBLK | (vnode->stream.type & S_IUMSK);
} else if (S_ISLNK(vnode->stream.type)) {
stat->st_size = vnode->stream.u.symlink.length;
}
return B_OK;
+7 -8
View File
@@ -805,18 +805,14 @@ static status_t
rootfs_read_link(fs_volume _fs, fs_vnode _link, char *buffer, size_t *_bufferSize)
{
struct rootfs_vnode *link = (rootfs_vnode*)_link;
size_t bufferSize = *_bufferSize;
if (!S_ISLNK(link->stream.type))
return B_BAD_VALUE;
*_bufferSize = link->stream.symlink.length + 1;
// we always need to return the number of bytes we intend to write!
if (link->stream.symlink.length < *_bufferSize)
*_bufferSize = link->stream.symlink.length;
if (bufferSize <= link->stream.symlink.length)
return B_BUFFER_OVERFLOW;
memcpy(buffer, link->stream.symlink.path, link->stream.symlink.length + 1);
memcpy(buffer, link->stream.symlink.path, *_bufferSize);
return B_OK;
}
@@ -975,7 +971,10 @@ rootfs_read_stat(fs_volume _fs, fs_vnode _v, struct stat *stat)
// stream exists, but we know to return size 0, since we can only hold directories
stat->st_dev = fs->id;
stat->st_ino = vnode->id;
stat->st_size = 0;
if (S_ISLNK(vnode->stream.type))
stat->st_size = vnode->stream.symlink.length;
else
stat->st_size = 0;
stat->st_mode = vnode->stream.type;
stat->st_nlink = 1;
+7 -2
View File
@@ -1780,9 +1780,13 @@ vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
}
if (FS_CALL(nextVnode, read_symlink) != NULL) {
bufferSize--;
status = FS_CALL(nextVnode, read_symlink)(
nextVnode->mount->cookie, nextVnode->private_node, buffer,
&bufferSize);
// null-terminate
if (status >= 0)
buffer[bufferSize] = '\0';
} else
status = B_BAD_VALUE;
@@ -7399,11 +7403,12 @@ _user_normalize_path(const char* userPath, bool traverseLink, char* buffer)
// read link
struct stat st;
if (FS_CALL(fileVnode, read_symlink) != NULL) {
size_t bufferSize = B_PATH_NAME_LENGTH;
size_t bufferSize = B_PATH_NAME_LENGTH - 1;
error = FS_CALL(fileVnode, read_symlink)(fileVnode->mount->cookie,
fileVnode->private_node, path, &bufferSize);
if (error != B_OK)
return error;
path[bufferSize] = '\0';
} else
return B_BAD_VALUE;
}
@@ -7704,7 +7709,7 @@ _user_read_link(int fd, const char *userPath, char *userBuffer, size_t *userBuff
if (status < B_OK)
return status;
if (user_strlcpy(userBuffer, buffer, bufferSize) < 0)
if (user_memcpy(userBuffer, buffer, bufferSize) != B_OK)
return B_BAD_ADDRESS;
return B_OK;
+9 -3
View File
@@ -20,13 +20,19 @@
ssize_t
readlink(const char *path, char *buffer, size_t bufferSize)
{
status_t status = _kern_read_link(-1, path, buffer, &bufferSize);
if (status < B_OK && status != B_BUFFER_OVERFLOW) {
size_t linkLen = bufferSize;
status_t status = _kern_read_link(-1, path, buffer, &linkLen);
if (status < B_OK) {
errno = status;
return -1;
}
return bufferSize;
// If the buffer is big enough, null-terminate the string. That's not
// required by the standard, but helps non-conforming apps.
if (linkLen < bufferSize)
buffer[linkLen] = '\0';
return linkLen;
}