libcamera: Add File helper class
The File helper class is a RAII wrapper for a file to manage the file handle and memory-mapped regions. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
parent
ec92318891
commit
bc207e808e
4 changed files with 425 additions and 0 deletions
352
src/libcamera/file.cpp
Normal file
352
src/libcamera/file.cpp
Normal file
|
@ -0,0 +1,352 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020, Google Inc.
|
||||||
|
*
|
||||||
|
* file.cpp - File I/O operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file file.h
|
||||||
|
* \brief File I/O operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace libcamera {
|
||||||
|
|
||||||
|
LOG_DEFINE_CATEGORY(File);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class File
|
||||||
|
* \brief Interface for I/O operations on files
|
||||||
|
*
|
||||||
|
* The File class provides an interface to perform I/O operations on files. It
|
||||||
|
* wraps opening, closing and mapping files in memory, and handles the cleaning
|
||||||
|
* of allocated resources.
|
||||||
|
*
|
||||||
|
* File instances are usually constructed with a file name, but the name can be
|
||||||
|
* set later through the setFileName() function. Instances are not automatically
|
||||||
|
* opened when constructed, and shall be opened explictly with open().
|
||||||
|
*
|
||||||
|
* Files can be mapped to the process memory with map(). Mapped regions can be
|
||||||
|
* unmapped manually with munmap(), and are automatically unmapped when the File
|
||||||
|
* is destroyed or when it is used to reference another file with setFileName().
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \enum File::MapFlag
|
||||||
|
* \brief Flags for the File::map() function
|
||||||
|
* \var File::MapNoOption
|
||||||
|
* \brief No option (used as default value)
|
||||||
|
* \var File::MapPrivate
|
||||||
|
* \brief The memory region is mapped as private, changes are not reflected in
|
||||||
|
* the file constents
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \enum File::OpenMode
|
||||||
|
* \brief Mode in which a file is opened
|
||||||
|
* \var File::NotOpen
|
||||||
|
* \brief The file is not open
|
||||||
|
* \var File::ReadOnly
|
||||||
|
* \brief The file is open for reading
|
||||||
|
* \var File::WriteOnly
|
||||||
|
* \brief The file is open for writing
|
||||||
|
* \var File::ReadWrite
|
||||||
|
* \brief The file is open for reading and writing
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Construct a File to represent the file \a name
|
||||||
|
* \param[in] name The file name
|
||||||
|
*
|
||||||
|
* Upon construction the File object is closed and shall be opened with open()
|
||||||
|
* before performing I/O operations.
|
||||||
|
*/
|
||||||
|
File::File(const std::string &name)
|
||||||
|
: name_(name), fd_(-1), mode_(NotOpen), error_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Construct a File without an associated name
|
||||||
|
*
|
||||||
|
* Before being used for any purpose, the file name shall be set with
|
||||||
|
* setFileName().
|
||||||
|
*/
|
||||||
|
File::File()
|
||||||
|
: fd_(-1), mode_(NotOpen), error_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Destroy a File instance
|
||||||
|
*
|
||||||
|
* Any memory mapping associated with the File is unmapped, and the File is
|
||||||
|
* closed if it is open.
|
||||||
|
*/
|
||||||
|
File::~File()
|
||||||
|
{
|
||||||
|
unmapAll();
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn const std::string &File::fileName() const
|
||||||
|
* \brief Retrieve the file name
|
||||||
|
* \return The file name
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the name of the file
|
||||||
|
* \param[in] name The name of the file
|
||||||
|
*
|
||||||
|
* The \a name can contain an absolute path, a relative path or no path at all.
|
||||||
|
* Calling this function on an open file results in undefined behaviour.
|
||||||
|
*
|
||||||
|
* Any memory mapping associated with the File is unmapped.
|
||||||
|
*/
|
||||||
|
void File::setFileName(const std::string &name)
|
||||||
|
{
|
||||||
|
if (isOpen()) {
|
||||||
|
LOG(File, Error)
|
||||||
|
<< "Can't set file name on already open file " << name_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unmapAll();
|
||||||
|
|
||||||
|
name_ = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check if the file specified by fileName() exists
|
||||||
|
*
|
||||||
|
* This function checks if the file specified by fileName() exists. The File
|
||||||
|
* instance doesn't need to be open to check for file existence, and this
|
||||||
|
* function may return false even if the file is open, if it was deleted from
|
||||||
|
* the file system.
|
||||||
|
*
|
||||||
|
* \return True if the the file exists, false otherwise
|
||||||
|
*/
|
||||||
|
bool File::exists() const
|
||||||
|
{
|
||||||
|
return exists(name_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Open the file in the given mode
|
||||||
|
* \param[in] mode The open mode
|
||||||
|
*
|
||||||
|
* This function opens the file specified by fileName() in \a mode. If the file
|
||||||
|
* doesn't exist and the mode is WriteOnly or ReadWrite, this
|
||||||
|
* function will attempt to create the file.
|
||||||
|
*
|
||||||
|
* The error() status is updated.
|
||||||
|
*
|
||||||
|
* \return True on success, false otherwise
|
||||||
|
*/
|
||||||
|
bool File::open(File::OpenMode mode)
|
||||||
|
{
|
||||||
|
if (isOpen()) {
|
||||||
|
LOG(File, Error) << "File " << name_ << " is already open";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags = (mode & ReadWrite) - 1;
|
||||||
|
|
||||||
|
fd_ = ::open(name_.c_str(), flags);
|
||||||
|
if (fd_ < 0) {
|
||||||
|
error_ = -errno;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode_ = mode;
|
||||||
|
error_ = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn bool File::isOpen() const
|
||||||
|
* \brief Check if the file is open
|
||||||
|
* \return True if the file is open, false otherwise
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn OpenMode File::openMode() const
|
||||||
|
* \brief Retrieve the file open mode
|
||||||
|
* \return The file open mode
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Close the file
|
||||||
|
*
|
||||||
|
* This function closes the File. If the File is not open, it performs no
|
||||||
|
* operation. Memory mappings created with map() are not destroyed when the
|
||||||
|
* file is closed.
|
||||||
|
*/
|
||||||
|
void File::close()
|
||||||
|
{
|
||||||
|
if (fd_ == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
::close(fd_);
|
||||||
|
fd_ = -1;
|
||||||
|
mode_ = NotOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn int File::error() const
|
||||||
|
* \brief Retrieve the file error status
|
||||||
|
*
|
||||||
|
* This function retrieves the error status from the last file open or I/O
|
||||||
|
* operation. The error status is a negative number as defined by errno.h. If
|
||||||
|
* no error occurred, this function returns 0.
|
||||||
|
*
|
||||||
|
* \return The file error status
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Retrieve the file size
|
||||||
|
*
|
||||||
|
* This function retrieves the size of the file on the filesystem. The File
|
||||||
|
* instance shall be open to retrieve its size. The error() status is not
|
||||||
|
* modified, error codes are returned directly on failure.
|
||||||
|
*
|
||||||
|
* \return The file size in bytes on success, or a negative error code otherwise
|
||||||
|
*/
|
||||||
|
ssize_t File::size() const
|
||||||
|
{
|
||||||
|
if (!isOpen())
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
int ret = fstat(fd_, &st);
|
||||||
|
if (ret < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
return st.st_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Map a region of the file in the process memory
|
||||||
|
* \param[in] offset The region offset within the file
|
||||||
|
* \param[in] size The region sise
|
||||||
|
* \param[in] flags The mapping flags
|
||||||
|
*
|
||||||
|
* This function maps a region of \a size bytes of the file starting at \a
|
||||||
|
* offset into the process memory. The File instance shall be open, but may be
|
||||||
|
* closed after mapping the region. Mappings stay valid when the File is
|
||||||
|
* closed, and are destroyed automatically when the File is deleted.
|
||||||
|
*
|
||||||
|
* If \a size is a negative value, this function maps the region starting at \a
|
||||||
|
* offset until the end of the file.
|
||||||
|
*
|
||||||
|
* The mapping memory protection is controlled by the file open mode, unless \a
|
||||||
|
* flags contains MapPrivate in which case the region is mapped in read/write
|
||||||
|
* mode.
|
||||||
|
*
|
||||||
|
* The error() status is updated.
|
||||||
|
*
|
||||||
|
* \return The mapped memory on success, or an empty span otherwise
|
||||||
|
*/
|
||||||
|
Span<uint8_t> File::map(off_t offset, ssize_t size, enum File::MapFlag flags)
|
||||||
|
{
|
||||||
|
if (!isOpen()) {
|
||||||
|
error_ = -EBADF;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < 0) {
|
||||||
|
size = File::size();
|
||||||
|
if (size < 0) {
|
||||||
|
error_ = size;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
size -= offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mmapFlags = flags & MapPrivate ? MAP_PRIVATE : MAP_SHARED;
|
||||||
|
|
||||||
|
int prot = 0;
|
||||||
|
if (mode_ & ReadOnly)
|
||||||
|
prot |= PROT_READ;
|
||||||
|
if (mode_ & WriteOnly)
|
||||||
|
prot |= PROT_WRITE;
|
||||||
|
if (flags & MapPrivate)
|
||||||
|
prot |= PROT_WRITE;
|
||||||
|
|
||||||
|
void *map = mmap(NULL, size, prot, mmapFlags, fd_, offset);
|
||||||
|
if (map == MAP_FAILED) {
|
||||||
|
error_ = -errno;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
maps_.emplace(map, size);
|
||||||
|
|
||||||
|
error_ = 0;
|
||||||
|
return { static_cast<uint8_t *>(map), static_cast<size_t>(size) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Unmap a region mapped with map()
|
||||||
|
* \param[in] addr The region address
|
||||||
|
*
|
||||||
|
* The error() status is updated.
|
||||||
|
*
|
||||||
|
* \return True on success, or false if an error occurs
|
||||||
|
*/
|
||||||
|
bool File::unmap(uint8_t *addr)
|
||||||
|
{
|
||||||
|
auto iter = maps_.find(static_cast<void *>(addr));
|
||||||
|
if (iter == maps_.end()) {
|
||||||
|
error_ = -ENOENT;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = munmap(addr, iter->second);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_ = -errno;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
maps_.erase(iter);
|
||||||
|
|
||||||
|
error_ = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::unmapAll()
|
||||||
|
{
|
||||||
|
for (const auto &map : maps_)
|
||||||
|
munmap(map.first, map.second);
|
||||||
|
|
||||||
|
maps_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check if the file specified by \a name exists
|
||||||
|
* \param[in] name The file name
|
||||||
|
* \return True if the file exists, false otherwise
|
||||||
|
*/
|
||||||
|
bool File::exists(const std::string &name)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int ret = stat(name.c_str(), &st);
|
||||||
|
if (ret < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace libcamera */
|
71
src/libcamera/include/file.h
Normal file
71
src/libcamera/include/file.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020, Google Inc.
|
||||||
|
*
|
||||||
|
* file.h - File I/O operations
|
||||||
|
*/
|
||||||
|
#ifndef __LIBCAMERA_FILE_H__
|
||||||
|
#define __LIBCAMERA_FILE_H__
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <libcamera/span.h>
|
||||||
|
|
||||||
|
namespace libcamera {
|
||||||
|
|
||||||
|
class File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum MapFlag {
|
||||||
|
MapNoOption = 0,
|
||||||
|
MapPrivate = (1 << 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum OpenMode {
|
||||||
|
NotOpen = 0,
|
||||||
|
ReadOnly = (1 << 0),
|
||||||
|
WriteOnly = (1 << 1),
|
||||||
|
ReadWrite = ReadOnly | WriteOnly,
|
||||||
|
};
|
||||||
|
|
||||||
|
File(const std::string &name);
|
||||||
|
File();
|
||||||
|
~File();
|
||||||
|
|
||||||
|
File(const File &) = delete;
|
||||||
|
File &operator=(const File &) = delete;
|
||||||
|
|
||||||
|
const std::string &fileName() const { return name_; }
|
||||||
|
void setFileName(const std::string &name);
|
||||||
|
bool exists() const;
|
||||||
|
|
||||||
|
bool open(OpenMode mode);
|
||||||
|
bool isOpen() const { return fd_ != -1; }
|
||||||
|
OpenMode openMode() const { return mode_; }
|
||||||
|
void close();
|
||||||
|
|
||||||
|
int error() const { return error_; }
|
||||||
|
ssize_t size() const;
|
||||||
|
|
||||||
|
Span<uint8_t> map(off_t offset = 0, ssize_t size = -1,
|
||||||
|
MapFlag flags = MapNoOption);
|
||||||
|
bool unmap(uint8_t *addr);
|
||||||
|
|
||||||
|
static bool exists(const std::string &name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void unmapAll();
|
||||||
|
|
||||||
|
std::string name_;
|
||||||
|
int fd_;
|
||||||
|
OpenMode mode_;
|
||||||
|
|
||||||
|
int error_;
|
||||||
|
std::map<void *, size_t> maps_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace libcamera */
|
||||||
|
|
||||||
|
#endif /* __LIBCAMERA_FILE_H__ */
|
|
@ -8,6 +8,7 @@ libcamera_headers = files([
|
||||||
'device_enumerator_sysfs.h',
|
'device_enumerator_sysfs.h',
|
||||||
'device_enumerator_udev.h',
|
'device_enumerator_udev.h',
|
||||||
'event_dispatcher_poll.h',
|
'event_dispatcher_poll.h',
|
||||||
|
'file.h',
|
||||||
'formats.h',
|
'formats.h',
|
||||||
'ipa_context_wrapper.h',
|
'ipa_context_wrapper.h',
|
||||||
'ipa_manager.h',
|
'ipa_manager.h',
|
||||||
|
|
|
@ -14,6 +14,7 @@ libcamera_sources = files([
|
||||||
'event_dispatcher.cpp',
|
'event_dispatcher.cpp',
|
||||||
'event_dispatcher_poll.cpp',
|
'event_dispatcher_poll.cpp',
|
||||||
'event_notifier.cpp',
|
'event_notifier.cpp',
|
||||||
|
'file.cpp',
|
||||||
'file_descriptor.cpp',
|
'file_descriptor.cpp',
|
||||||
'formats.cpp',
|
'formats.cpp',
|
||||||
'framebuffer_allocator.cpp',
|
'framebuffer_allocator.cpp',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue