[libcamera-devel,v2,1/4] libcamera: file: Add read/write support

Message ID 20200714090936.9562-1-laurent.pinchart@ideasonboard.com
State Accepted
Commit 25288281d1e72c8e6c264525926a200511407ac7
Headers show
Series
  • [libcamera-devel,v2,1/4] libcamera: file: Add read/write support
Related show

Commit Message

Laurent Pinchart July 14, 2020, 9:09 a.m. UTC
Add basic support to read and write data from/to a file, along with
retrieving and setting the current read/write position.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
Changes since v1:

- Don't cache pos(), use lseek()
---
 include/libcamera/internal/file.h |   6 ++
 src/libcamera/file.cpp            | 109 ++++++++++++++++++++++++++++++
 2 files changed, 115 insertions(+)

Patch

diff --git a/include/libcamera/internal/file.h b/include/libcamera/internal/file.h
index e3e72132e336..9b6d011f5e9d 100644
--- a/include/libcamera/internal/file.h
+++ b/include/libcamera/internal/file.h
@@ -49,6 +49,12 @@  public:
 	int error() const { return error_; }
 	ssize_t size() const;
 
+	off_t pos() const;
+	off_t seek(off_t pos);
+
+	ssize_t read(const Span<uint8_t> &data);
+	ssize_t write(const Span<const uint8_t> &data);
+
 	Span<uint8_t> map(off_t offset = 0, ssize_t size = -1,
 			  MapFlag flags = MapNoOption);
 	bool unmap(uint8_t *addr);
diff --git a/src/libcamera/file.cpp b/src/libcamera/file.cpp
index c471bde3fc68..d99a1806e1c8 100644
--- a/src/libcamera/file.cpp
+++ b/src/libcamera/file.cpp
@@ -237,6 +237,115 @@  ssize_t File::size() const
 	return st.st_size;
 }
 
+/**
+ * \brief Return current read or write position
+ *
+ * If the file is closed, this function returns 0.
+ *
+ * \return The current read or write position
+ */
+off_t File::pos() const
+{
+	if (!isOpen())
+		return 0;
+
+	return lseek(fd_, 0, SEEK_CUR);
+}
+
+/**
+ * \brief Set the read or write position
+ * \param[in] pos The desired position
+ * \return The resulting offset from the beginning of the file on success, or a
+ * negative error code otherwise
+ */
+off_t File::seek(off_t pos)
+{
+	if (!isOpen())
+		return -EINVAL;
+
+	off_t ret = lseek(fd_, pos, SEEK_SET);
+	if (ret < 0)
+		return -errno;
+
+	return ret;
+}
+
+/**
+ * \brief Read data from the file
+ * \param[in] data Memory to read data into
+ *
+ * Read at most \a data.size() bytes from the file into \a data.data(), and
+ * return the number of bytes read. If less data than requested is available,
+ * the returned byte count may be smaller than the requested size. If no more
+ * data is available, 0 is returned.
+ *
+ * The position of the file as returned by pos() is advanced by the number of
+ * bytes read. If an error occurs, the position isn't modified.
+ *
+ * \return The number of bytes read on success, or a negative error code
+ * otherwise
+ */
+ssize_t File::read(const Span<uint8_t> &data)
+{
+	if (!isOpen())
+		return -EINVAL;
+
+	size_t readBytes = 0;
+	ssize_t ret = 0;
+
+	/* Retry in case of interrupted system calls. */
+	while (readBytes < data.size()) {
+		ret = ::read(fd_, data.data() + readBytes,
+			     data.size() - readBytes);
+		if (ret <= 0)
+			break;
+
+		readBytes += ret;
+	}
+
+	if (ret < 0 && !readBytes)
+		return -errno;
+
+	return readBytes;
+}
+
+/**
+ * \brief Write data to the file
+ * \param[in] data Memory containing data to be written
+ *
+ * Write at most \a data.size() bytes from \a data.data() to the file, and
+ * return the number of bytes written. If the file system doesn't have enough
+ * space for the data, the returned byte count may be less than requested.
+ *
+ * The position of the file as returned by pos() is advanced by the number of
+ * bytes written. If an error occurs, the position isn't modified.
+ *
+ * \return The number of bytes written on success, or a negative error code
+ * otherwise
+ */
+ssize_t File::write(const Span<const uint8_t> &data)
+{
+	if (!isOpen())
+		return -EINVAL;
+
+	size_t writtenBytes = 0;
+
+	/* Retry in case of interrupted system calls. */
+	while (writtenBytes < data.size()) {
+		ssize_t ret = ::write(fd_, data.data() + writtenBytes,
+				      data.size() - writtenBytes);
+		if (ret <= 0)
+			break;
+
+		writtenBytes += ret;
+	}
+
+	if (data.size() && !writtenBytes)
+		return -errno;
+
+	return writtenBytes;
+}
+
 /**
  * \brief Map a region of the file in the process memory
  * \param[in] offset The region offset within the file