+ * \sa para_open(), mmap(2).
+ */
+int mmap_full_file(const char *path, int open_mode, void **map,
+ size_t *size, int *fd_ptr)
+{
+ int fd, ret, mmap_prot, mmap_flags;
+ struct stat file_status;
+
+ if (open_mode == O_RDONLY) {
+ mmap_prot = PROT_READ;
+ mmap_flags = MAP_PRIVATE;
+ } else {
+ mmap_prot = PROT_READ | PROT_WRITE;
+ mmap_flags = MAP_SHARED;
+ }
+ ret = para_open(path, open_mode, 0);
+ if (ret < 0)
+ return ret;
+ fd = ret;
+ if (fstat(fd, &file_status) < 0) {
+ ret = -ERRNO_TO_PARA_ERROR(errno);
+ goto out;
+ }
+ *size = file_status.st_size;
+ /*
+ * If the file is empty, *size is zero and mmap() would return EINVAL
+ * (Invalid argument). This error is common enough to spend an extra
+ * error code which explicitly states the problem.
+ */
+ ret = -E_EMPTY;
+ if (*size == 0)
+ goto out;
+ /*
+ * If fd refers to a directory, mmap() returns ENODEV (No such device),
+ * at least on Linux. "Is a directory" seems to be more to the point.
+ */
+ ret = -ERRNO_TO_PARA_ERROR(EISDIR);
+ if (S_ISDIR(file_status.st_mode))
+ goto out;
+
+ ret = para_mmap(*size, mmap_prot, mmap_flags, fd, map);
+out:
+ if (ret < 0 || !fd_ptr)
+ close(fd);
+ else
+ *fd_ptr = fd;
+ return ret;
+}
+
+/**
+ * A wrapper for munmap(2).
+ *
+ * \param start The start address of the memory mapping.
+ * \param length The size of the mapping.
+ *
+ * If NULL is passed as the start address, the length value is ignored and the
+ * function does nothing.
+ *
+ * \return Zero if NULL was passed, one if the memory area was successfully
+ * unmapped, a negative error code otherwise.
+ *
+ * \sa munmap(2), \ref mmap_full_file().
+ */
+int para_munmap(void *start, size_t length)
+{
+ if (!start)
+ return 0;
+ if (munmap(start, length) >= 0)
+ return 1;
+ return -ERRNO_TO_PARA_ERROR(errno);
+}
+
+/**
+ * Simple wrapper for poll(2).