Boost - mmaping a file into memory for reads&writes - c++

I'm trying to map a region of a particular size into the memory, looking at the docs example:
https://www.boost.org/doc/libs/1_70_0/doc/html/interprocess/sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file
as you can notice, boost version is 1.70.0
using namespace boost::interprocess;
const char *FileName = "c_e_d.bin";
const std::size_t FileSize = 10000;
file_mapping::remove(FileName);
std::filebuf fbuf;
auto p = fbuf.open(FileName, std::ios_base::in | std::ios_base::out
| std::ios_base::trunc | std::ios_base::binary);
//Set the size
auto r = fbuf.pubseekoff(FileSize-1, std::ios_base::beg);
auto r2 = fbuf.sputc(0);
//Create a file mapping
file_mapping m_file(FileName, read_write);
//Map the whole file with read-write permissions in this process
mapped_region region(m_file, read_write);
but an exception occurs:
I don't need the parent-child functionality, just many threads writing directly to a mmaped region of memory.
Can somebody help me solve this out please?
Thank you in advance.
Additional debug info:
p is created seemed to be:
It is also seemed to be that the two following operations did work:

Your fbuf doesn't sync. Either sync or limit the scope to get implicit sync on destruction.
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <fstream>
namespace bip = boost::interprocess;
int main()
{
const char* FileName = "c_e_d.bin";
const std::size_t FileSize = 10000;
bip::file_mapping::remove(FileName);
{
std::filebuf fbuf;
/*auto p =*/fbuf.open(FileName,
std::ios_base::in | std::ios_base::out |
std::ios_base::trunc |
std::ios_base::binary);
// Set the size
fbuf.pubseekoff(FileSize - 1, std::ios_base::beg);
fbuf.sputc(0);
fbuf.pubsync();
}
// Create a file mapping
bip::file_mapping m_file(FileName, bip::read_write);
// Map the whole file with read-write permissions in this process
bip::mapped_region region(m_file, bip::read_write);
}

Related

ifstream No such file or directory C++

So I'm trying to write a shader class in C++ similar to this. This is my file structure:
| -- /source
| | -- main.cpp
| | -- /Shaders
| | | -- Shader.h
| | | -- shader.frag
| | | -- shader.vert
In my main.cpp file, I import shaders.h. Shaders.h constains the shader class, which reads in shader code from the shader.frag and shader.vert files (or so it should). The path I pass from main.cpp is Shaders/shader.frag and Shaders/shader.vert, and I am getting the error No such file or directory.
Here is my (or their) relevant shader code:
#ifndef SHADER_H
#define SHADER_H
#include <glad/glad.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
Shader(const char* vertexPath, const char* fragmentPath)
{
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensure ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
// open files
vShaderFile.open(vertexPath); <------- this is where it is getting caught
fShaderFile.open(fragmentPath); <---------- and i assume it would be here as well
std::stringstream vShaderStream, fShaderStream;
// read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure e)
{
char buffer[256];
strerror_s(buffer, 256, errno);
printf("ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ: %s\n", buffer);
}
...
I have tried multiple different path variations. I've tried passing an absolute path as well, and consistently get the same error. I would really appreciate any help with this.
You just need to include the <fstream> library.

Linux Shared Memory with C++: Segmentation Fault

I'm following the Linux Programming Interface book (page 1004-1005).
I know the book uses C. But I'd like to implement the same behavior in C++. That is: share a struct between processes through shared memory.
#include <iostream>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
struct my_pair {
int a;
int b;
};
int main()
{
key_t key = ftok("aaaaa", 1);
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT);
my_pair *numbers;
numbers = shmat(shmid, NULL, 0);
cout << numbers->a;
return 0;
}
It gives me this error:
shteste.cpp: In function 'int main()':
shteste.cpp:18: error: invalid conversion from 'void*' to 'my_pair*'
I understand that C++ is more strict. If I cast the return of shmat to (my_pair *), it compiles but gives me segmentation fault during execution.
Is it possible (how) to use Linux / C shared memory facilities with C++ ?
I'm compiling with: G++ 4.4.7: g++ shteste.cpp -o shteste -std=c++0x
Thanks...
EDIT: Following all sugestions, this is the code now:
int main()
{
key_t key;
if ((key = ftok("/home/alunos/scd/g11/aaaaa", 1)) == (key_t) -1) {
perror("IPC error: ftok"); exit(1);
}
int shmid = shmget(key , sizeof(my_pair), IPC_CREAT | 0640);
if (shmid == -1) {
perror("Could not get shared memory");
return EXIT_FAILURE;
}
my_pair *numbers;
void* mem = (my_pair*) shmat(shmid, NULL, 0);
if (mem == reinterpret_cast<void*>(-1)) {
perror("Could not get shared memory location");
return EXIT_FAILURE;
} else {
numbers = reinterpret_cast<my_pair*>(mem);
cout << numbers->a;
}
return EXIT_SUCCESS;
}
aaaaa contents: notacat
[scd11#VM11 ~]$ ./shteste
Could not get shared memory: Permission denied
This is likely a permissions issue. You can check the return values of shmget and shmat and use perror to print a human-readable error message like this.
#include <iostream>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
struct my_pair {
int a;
int b;
};
int main()
{
key_t key = ftok("aaaaa", 1);
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT | 0777);
if (shmid == -1) {
perror("Could not get shared memory");
return EXIT_FAILURE;
}
my_pair *numbers;
void* mem = (my_pair*) shmat(shmid, NULL, 0);
if (mem == reinterpret_cast<void*>(-1)) {
perror("Could not get shared memory location");
return EXIT_FAILURE;
} else {
numbers = reinterpret_cast<my_pair*>(mem);
cout << numbers->a;
}
return EXIT_SUCCESS;
}
You simple forget to set the permissions:
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT | 0777);
As I already mentioned in my comment, the result of the failing command can be seen with strace.
64 5327 shmget(0xffffffff, 8, IPC_CREAT|000) = 11534358
65 5327 shmat(11534358, NULL, 0) = -1 EACCES (Permission denied)"
If your file "aaaaa" is existing, the code works for me.
This is a permissions issue.
Per the shmget() documentation:
SYNOPSIS
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
...
DESCRIPTION
...
The low-order nine bits of shm_perm.mode are set to the low-order nine bits of shmflg.
You didn't set any permission bits. The low-order nine bits of shmflag in your call are all zero:
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT);
You need to set the proper permissions, something like this:
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT|0640);
You will also likely have to use ipcrm to remove the current shared-memory segment, as it will remain as-is with the incorrect permssions. Even if you change your code, your shmget() calls will return the id of the existing segment - the one that you can't attach because the permissions are missing.
First, use ipcs -a to list the shared memory segments, then use ipcrm -m shmid or ipcrm -M shmkey to remove the segment with incorrect permissions.
According to ftok man page:
The ftok() function uses the identity of the file named by the given
pathname (which must refer to an existing, accessible file).
With existing file your code will work.
Alternatively you can use:
key = IPC_PRIVATE
which will be sufficient for this example, but will not work for real IPC.

Why does O_CREAT create files only accessible by administrators?

I have the following simple program:
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <string>
using namespace std;
int main() {
string data { "The quick brown fox jumps over the lazy dog" };
int file_descriptor = open("some_file.txt", O_CREAT | O_WRONLY);
write(file_descriptor, data.c_str(), data.size());
cout << file_descriptor << endl;
return 0;
}
which for the most part works fine - the data is outputted into the file. But per http://linux.die.net/man/2/open , the O_CREAT flag should set the file owner to the effective user ID of the process. I'm compiling/running my application from the terminal, but not with any sort of privileges, so why is the created file only visible to administrators?
Random mischance. When you use O_CREAT, open() is a 3-argument function, which takes the file mode as the third argument.
You should be using:
int fd = open("some_file.txt", O_CREATE | O_WRONLY, 0444);
This will create a file with no write permission for anybody (but which your process will be able to write to).
See <sys/stat.h> for more information about the POSIX symbolic constants to use in place of 0444.

ifstream creates file if it doesn't exist

I'm having some trouble writing a Linux console app which reads apache logs.
I need to handle bash script arguments, the last one being a path to the log file.
My problem is that if the file doesn't exist, I would like to throw an exception.
But when I try to open the file in read-only mode, instead of failing it creates the file !
Here's the code :
// logreader.h
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <stdexcept>
class LogReader
{
public:
LogReader(int, const char **);
virtual ~LogReader();
// ...
private:
std::ifstream log_;
};
// logreader.cpp
#include <logreader.h>
LogReader::LogReader(int argc, const char ** argv):
log_()
{
log_.exceptions(std::ifstream::failbit | std::ifstream::badbit);
for (int i = 1; i < argc; ++i)
{
std::string arg(argv[i]);
if (i == argc - 1)
{
try
{
log_.open(arg.c_str(), std::ifstream::in);
}
catch (std::ifstream::failure)
{
throw std::runtime_error("The file " + arg + " wasn't opened");
}
}
}
}
LogReader::~LogReader()
{
}
// main.cpp
#include <logreader.h>
int main(int argc, const char ** argv)
{
LogReader(argc, argv);
return 0;
}
Script call:
jmcomets $ ./test -g -l
jmcomets $ ls -l
-rw-rw-r-- 1 jmcomets jmcomets 0 Nov 14 22:41 -l
Since you are opening an std::ifstream it is necessary to add std::ios_base::in (or any other spelling of the std::ios_base::openmode) according to 27.9.1.9 [ifstream.members] paragraph 4: The flag is automatically added by the call to open(). Note that an std::ofstream or an std::fstream would automatically add std::ios_base::out (27.9.1.13 [ofstream.members] paragrpah 3) or std::ios_base::in | std::ios_base::out (27.9.1.17 [fstream.members] paragraph 3), both of which resulting in a new file being created if it doesn't exist (and there are write permissions, etc.).
If the code you posted creates a new file, the implementation of the standard C++ library is wrong: when only the flag std::ios_base::in is specified, the file is open "as if" using the open mode "r" with fopen() (27.9.1.4 [filebuf.members] paragraph 5). fopen() in turn doesn't create a new file when it gets an open mode of "r" (7.21.5.3 paragraph 3).
You can set the failbit in the exceptions flag for the ifstream:
std::ifstream log;
log.exceptions ( std::ifstream::failbit );
try {
log.open ("test.txt");
}
catch (std::ifstream::failure e) {
std::cout << "Exception opening/reading file\n";
}
Source
I've tested, and ifstream will throw a failure exception if the file cannot be opened, e.g. file not found, no read permissions. It will open read-only.
You need to specify ifstream::in as a second parameter as:
log.open(arg.c_str(), ifstream::in)
You can also do:
std::ifstream log(arg.c_str(), ifstream::in);
and skip the call to open()
Edit with something Linux compatible;
Try opening with fopen before writing. If the file DNE the FILE pointer will be null.
FILE * file;
file = fopen ("myfile.txt","r");
if (file == NULL)
//throw if fopen didn't already.
else
//do stuff with my file

On Windows is there an interface for Copying Folders?

I want to copy folder A and paste to desktop.
I am currently using C++ so preferably an OO interface if available.
On Windows (Win32), you could use SHFileOperation, eg:
SHFILEOPSTRUCT s = { 0 };
s.hwnd = m_hWnd;
s.wFunc = FO_COPY;
s.fFlags = FOF_SILENT;
s.pTo = "C:\\target folder\0";
s.pFrom = "C:\\source folder\\*\0";
SHFileOperation(&s);
Use this
bool CopyDirTo( const wstring& source_folder, const wstring& target_folder )
{
wstring new_sf = source_folder + L"\\*";
WCHAR sf[MAX_PATH+1];
WCHAR tf[MAX_PATH+1];
wcscpy_s(sf, MAX_PATH, new_sf.c_str());
wcscpy_s(tf, MAX_PATH, target_folder.c_str());
sf[lstrlenW(sf)+1] = 0;
tf[lstrlenW(tf)+1] = 0;
SHFILEOPSTRUCTW s = { 0 };
s.wFunc = FO_COPY;
s.pTo = tf;
s.pFrom = sf;
s.fFlags = FOF_SILENT | FOF_NOCONFIRMMKDIR | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NO_UI;
int res = SHFileOperationW( &s );
return res == 0;
}
Starting with Visual Studio 2015 you can use std::filesystem::copy which is even platform independent since it is available in implementations supporting >= C++17.
#include <exception>
#include <experimental/filesystem> // C++-standard filesystem header file in VS15, VS17.
#include <iostream>
namespace fs = std::experimental::filesystem; // experimental for VS15, VS17.
/*! Copies all contents of path/to/source/directory to path/to/target/directory.
*/
int main()
{
fs::path source = "path/to/source/directory";
fs::path targetParent = "path/to/target";
auto target = targetParent / source.filename(); // source.filename() returns "directory".
try // If you want to avoid exception handling then use the error code overload of the following functions.
{
fs::create_directories(target); // Recursively create target directory if not existing.
fs::copy(source, target, fs::copy_options::recursive);
}
catch (std::exception& e) // Not using fs::filesystem_error since std::bad_alloc can throw too.
{
std::cout << e.what();
}
}
Change the behaviour of fs::copy with std::filesystem::copy_options. I've used std::filesystem::path::filename to retrieve the source directory name without having to type it manually.
(assuming Windows)
Use can use ShFileOperation (or IFileOperation::CopyItem on Vista).
Max.
For a platform agnostic solution, I'd suggest Boost::filesystem. That link is basically the reference material. There is a copy_file method that copies a file from one location to another.
On Windows, the desktop is a special folder:
// String buffer for holding the path.
TCHAR strPath[ MAX_PATH ];
// Get the special folder path.
SHGetSpecialFolderPath(
0, // Hwnd
strPath, // String buffer.
CSIDL_DESKTOPDIRECTORY, // CSLID of folder
FALSE ); // Create if doesn't exists?
Here's an example using SHFileOperation:
http://msdn.microsoft.com/en-us/library/bb776887%28VS.85%29.aspx#example
Here's a quick hack without it:
#import <stdlib.h>
int main(int argc, char *argv[]) {
system("robocopy \"C:\\my\\folder\" \"%userprofile%\\desktop\\\" /MIR");
return 0;
}
it works
#include <iostream>
int main()
{
system("xcopy C:\\Users\\Elmi\\Desktop\\AAAAAA\ C:\\Users\\Elmi\\Desktop\\b\ /e /i /h");
return 0;
}