Commit 5ccbaeff authored by Chris Friedt's avatar Chris Friedt Committed by Henrik Brix Andersen
Browse files

posix: device_io: implement pread() and pwrite()



Add pread() and pwrite() implementations, which are nearly
identical to read() and write() but differ in that they do not
update the file-descriptor offset and instead read from a
specific file offset.

Signed-off-by: default avatarChris Friedt <cfriedt@tenstorrent.com>
parent fe26de96
Loading
Loading
Loading
Loading
+41 −13
Original line number Diff line number Diff line
@@ -302,9 +302,21 @@ int zvfs_alloc_fd(void *obj, const struct fd_op_vtable *vtable)
	return fd;
}

static ssize_t zvfs_rw(int fd, void *buf, size_t sz, bool is_write)
static bool supports_pread_pwrite(uint32_t mode)
{
	switch (mode & ZVFS_MODE_IFMT) {
	case ZVFS_MODE_IFSHM:
		return true;
	default:
		return false;
	}
}

static ssize_t zvfs_rw(int fd, void *buf, size_t sz, bool is_write, const size_t *from_offset)
{
	bool prw;
	ssize_t res;
	const size_t *off;

	if (_check_fd(fd) < 0) {
		return -1;
@@ -312,24 +324,40 @@ static ssize_t zvfs_rw(int fd, void *buf, size_t sz, bool is_write)

	(void)k_mutex_lock(&fdtable[fd].lock, K_FOREVER);

	prw = supports_pread_pwrite(fdtable[fd].mode);
	if (from_offset != NULL && !prw) {
		/*
		 * Seekable file types should support pread() / pwrite() and per-fd offset passing.
		 * Otherwise, it's a bug.
		 */
		errno = ENOTSUP;
		res = -1;
		goto unlock;
	}

	/* If there is no specified from_offset, then use the current offset of the fd */
	off = (from_offset == NULL) ? &fdtable[fd].offset : from_offset;

	if (is_write) {
		if (fdtable[fd].vtable->write_offset == NULL) {
		if (fdtable[fd].vtable->write_offs == NULL) {
			res = -1;
			errno = EIO;
		} else {
			res = fdtable[fd].vtable->write_offset(fdtable[fd].obj, buf, sz,
							       fdtable[fd].offset);
			res = fdtable[fd].vtable->write_offs(fdtable[fd].obj, buf, sz, *off);
		}
	} else {
		if (fdtable[fd].vtable->read == NULL) {
		if (fdtable[fd].vtable->read_offs == NULL) {
			res = -1;
			errno = EIO;
		} else {
			res = fdtable[fd].vtable->read_offset(fdtable[fd].obj, buf, sz,
							      fdtable[fd].offset);
			res = fdtable[fd].vtable->read_offs(fdtable[fd].obj, buf, sz, *off);
		}
	}
	if (res > 0) {
	if (res > 0 && prw && from_offset == NULL) {
		/*
		 * only update the fd offset when from_offset is not specified
		 * See pread() / pwrite()
		 */
		fdtable[fd].offset += res;
	}

@@ -339,14 +367,14 @@ unlock:
	return res;
}

ssize_t zvfs_read(int fd, void *buf, size_t sz)
ssize_t zvfs_read(int fd, void *buf, size_t sz, const size_t *from_offset)
{
	return zvfs_rw(fd, buf, sz, false);
	return zvfs_rw(fd, buf, sz, false, from_offset);
}

ssize_t zvfs_write(int fd, const void *buf, size_t sz)
ssize_t zvfs_write(int fd, const void *buf, size_t sz, const size_t *from_offset)
{
	return zvfs_rw(fd, (void *)buf, sz, true);
	return zvfs_rw(fd, (void *)buf, sz, true, from_offset);
}

int zvfs_close(int fd)
@@ -488,7 +516,7 @@ static ssize_t stdinout_read_vmeth(void *obj, void *buffer, size_t count)
static ssize_t stdinout_write_vmeth(void *obj, const void *buffer, size_t count)
{
#if defined(CONFIG_BOARD_NATIVE_POSIX)
	return zvfs_write(1, buffer, count);
	return zvfs_write(1, buffer, count, NULL);
#elif defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_ARCMWDT_LIBC)
	return z_impl_zephyr_write_stdout(buffer, count);
#else
+28 −4
Original line number Diff line number Diff line
@@ -15,8 +15,8 @@
/* prototypes for external, not-yet-public, functions in fdtable.c or fs.c */
int zvfs_close(int fd);
int zvfs_open(const char *name, int flags);
ssize_t zvfs_read(int fd, void *buf, size_t sz);
ssize_t zvfs_write(int fd, const void *buf, size_t sz);
ssize_t zvfs_read(int fd, void *buf, size_t sz, size_t *from_offset);
ssize_t zvfs_write(int fd, const void *buf, size_t sz, size_t *from_offset);

int close(int fd)
{
@@ -41,9 +41,33 @@ int poll(struct pollfd *fds, int nfds, int timeout)
	return zsock_poll(fds, nfds, timeout);
}

ssize_t pread(int fd, void *buf, size_t count, off_t offset)
{
	size_t off = (size_t)offset;

	if (offset < 0) {
		errno = EINVAL;
		return -1;
	}

	return zvfs_read(fd, buf, count, (size_t *)&off);
}

ssize_t pwrite(int fd, void *buf, size_t count, off_t offset)
{
	size_t off = (size_t)offset;

	if (offset < 0) {
		errno = EINVAL;
		return -1;
	}

	return zvfs_write(fd, buf, count, (size_t *)&off);
}

ssize_t read(int fd, void *buf, size_t sz)
{
	return zvfs_read(fd, buf, sz);
	return zvfs_read(fd, buf, sz, NULL);
}
#ifdef CONFIG_POSIX_DEVICE_IO_ALIAS_READ
FUNC_ALIAS(read, _read, ssize_t);
@@ -57,7 +81,7 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struc

ssize_t write(int fd, const void *buf, size_t sz)
{
	return zvfs_write(fd, buf, sz);
	return zvfs_write(fd, buf, sz, NULL);
}
#ifdef CONFIG_POSIX_DEVICE_IO_ALIAS_WRITE
FUNC_ALIAS(write, _write, ssize_t);