I'm attempting to automate some image processing, and once I have processed an image I would like to move it to another directory.
I have tried using std::experimental::filesystem::copy and std::experimental::filesystem::copy_file, but I get an error of "Could not copy file: copy_file(p1, p2, options): invalid arguments: operation not permitted"
#include <filesystem>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, const char* argv[]) {
if (argc < 2) {
cout << "no directory specified" << endl;
return 0;
}
experimental::filesystem::path inputPath(argv[1]);
experimental::filesystem::path
for (auto const & entry : experimental::filesystem::directory_iterator(inputPath)) {
string src = entry.path().string();
experimental::filesystem::path dest("C:\\Users\\Keelan\\Desktop\\MatchTest\\IMG_Copy\\"+ entry.path().filename().string());
cout << entry.path() << endl;
cout << "Copying " << src << " to " << dest << endl;
experimental::filesystem::copy_file(entry.path(), dest, experimental::filesystem::copy_options::none);
}
return 0;
}
I have so far had no success using the either of these copy functions. I have seen other solutions involving redirecting file-streams but I don't think this is appropriate given I will be processing files on demand and need to minimise response time.
EDIT: the folder I'm copying to exists and all users have read/write permissions
EDIT 2: I deleted and recreated the folder and the problem is fixed, not sure of the reason why
There are 2 potential issues here:
Since you use experimental::filesystem::copy_options::none you will get an exception if the file already exists - see the paragraph "Otherwise, if the destination file already exists" here
If the source folder contains subfolders with files, the directory_iterator will iterate them as well, but if you attempt to copy a file nested deeper, you need to create the target directory hierarchy as well.
Related
This is not a duplicate. I'm trying to print some output to a file in a subdirectory (in this case to a file /stuff/output_1.txt) but it doesn't seem to create any new file. The code executes but no file is created, nor any subdirectory called /stuff. Here is my code:
#include <iostream>
#include <sstream>
#include <fstream>
using namespace std;
int main(void)
{
int out = 1;
stringstream fname;
fstream f;
fname << "./stuff/output" << "_" << out << ".txt";
f.open(fname.str().c_str(), ios_base::out);
f << "hello" << "\t";
f << endl;
f.close();
}
When I instead use the line
fname << "output" << "_" << out << ".txt";
It creates a file called output_1.txt in the current directory so the rest of the code clearly works. What is going wrong?
I'm on macOS so the "/" should be correct instead of the "\" used on Windows, no?
no file is created, nor any subdirectory
You are using fstream which expects the path to exist. If you are referencing a directory and it doesn't exist, then it will fail, because either you have to create the directory before you run your program, or you have to use mkdir() to create it.
You can check with f.is_open() if your stream could be opened.
f.open(fname.str().c_str(), ios_base::out);
if (f.is_open())
{
f << "hello" << "\t";
f << endl;
f.close();
}
else
std::cerr << "Unable to open " << fname;
nor any subdirectory called ./stuff
Why did you expect fstream to create subdirectories for you ? You have to do that yourself. I got the same behaviour when testing it on my machine, and the simple solution was to do a mkdir stuff. After that, the file got correctly created. But I think it's weird no runtime error is thrown. It's not good (especially for beginners) that fstream jsut silently does nothing when the subdirectory is not existing.
I am trying to open a text file, and the code below is my attempt:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
std::ifstream file;
file.open("InputFile.txt");
std::string fileOutput;
if (file.is_open())
{
while (!file.eof())
{
file >> fileOutput;
std::cout << fileOutput << std::endl;
}
}
else
{
std::cout << "File failed to open" << std::endl;
}
file.close();
return 0;
}
The text file is located on my desktop, and it only contain two integers.
Whenever I run the code above, it will show me the "file failed to open" message. I am completely new to c++, so I really don’t have any idea why my code is not working. So any comments would be appreciated.
The text file is located on my desktop
So where is your C++ source file, is it located in my desktop as well?
Note this code file.open("InputFile.txt"); tries to open the InputFile.txt in the current folder, that means it only works if both C++ source file and your text file are in the same folder. That seems to be your problem.
Like #ShadowRanger's this comment, the existing answers are both inaccurate. The argument for file.open() needs to either 1. reflect the relative location of the text file in relation to the current working directory (where you are calling the executable from), or 2. give the absolute location of the text file on the disc.
I suggest the following solution:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char** argv) {
if (argc != 2) {
std::cout << "incorrect number of inputs" << "\n";
std::cout << "correct usage: this_executable.exe file_location" << "\n";
return -1;
}
std::ifstream file;
file.open(argv[1]);
std::string fileOutput;
if (file.is_open())
{
while (file >> fileOutput)
{
std::cout << fileOutput << std::endl;
}
}
else
{
std::cout << "File "<< argv[1] <<" failed to open" << std::endl;
}
file.close();
return 0;
}
This solution takes the file's address info out of the code. With this solution, when you call your executable, the file's address(directory path + file name) is given to the executable at run-time rather than compile-time. Now, you'd run the executable like:
C:\path_to_your_exe>my_executable.exe C:\path_of_your_txt_file\InputFile.txt
The benefits of this approach are:
You can change the file's name / path without having to recompile the code;
On the commandline, it is easier to check that the target file's address is correct by tab completion
Also note:
As #ShadowRanger also pointed out the Why is “while ( !feof (file) )” always wrong? issue which I was not aware of.
If you are wondering what argv[1] means, see this guide for more information on commandline arguments for C++. You also want to make sure to catch situations when the user did not specify an input (meaning argv[1] is invalid, thus the argc != 2)
Unless the file you are opening and your executable are in the same directory, the same message will be printed since it will search for the file in the current working directory. You can specify the absolute path to the file on your desktop using %USERPROFILE%\\Desktop\\InputFile.txt or any other environmental variable that maps the absolute path of a disk, from which your file can be found.
I am trying to create a directory inside program files, but my code failed. I can make folder directly on the root, so this is very strange I think.
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <direct.h> // _mkdir
int _tmain(int argc, _TCHAR* argv[])
{
// Make directory
if(_mkdir("C:\\Program Files\\MyProgram") == 0 ){
cout << "Folder created" << endl;
}
else{
cout << "Folder creation failed" << endl;
}
// Pause program
system("PAUSE");
return 0;
}
Edit:
Thank you. I understand that c:\Program files\MyProgram is only for install files, but where should I put save files? Example save files for a C++ game. Should they be stored in "C:\Users\Username\Documents\MyProgram"?
The proper folder name to write depends on version and localization.
A simple way to get that name is to search for the APPDATA environment variable.
See here to get an environment variable, and here about the recognized environment variables and meanings.
I'm trying to write a program to parse the first and sixteenth columns of a CSV file (converted into .txt). I have the CSV ("posts.txt") document in the folder with the executable. But, whenever I try to run the executable, my program delivers that it cannot open the file (or that "!infile.is_open()"). Mind giving me some assistance? I'm running in Xcode 3.2.3 on Mac OSX 10.8.3. The code is shows below.
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string.h>
using namespace std;
void answeredPostGrabber()
{
ifstream inFile("posts.txt");
string postNumber;
string answerNumber;
string throwAway;
if(inFile.is_open())
{
while(inFile.good())
{
getline(inFile,postNumber,',');
cout << postNumber << ",";
for(int y=1;y++;y<16)
{
getline(inFile,throwAway,',');
}
getline(inFile,answerNumber,',');
cout << answerNumber << endl;
ofstream edges;
edges.open("edges.txt",ios::app);
edges << postNumber << "," << answerNumber<< endl;
edges.close();
ofstream nodes;
nodes.open("nodes.txt",ios::app);
nodes << postNumber << "\n" << answerNumber << endl;
nodes.close();
getline(inFile,throwAway);
}
}else cout << "ERROR: Unable to open file." << endl;
}
int main ()
{
answeredPostGrabber();
return 0;
}
Thank you in advance!
I have the CSV ("posts.txt") document in the folder with the executable.
The file should be present in the current working directory of your process, which may or may not be the same directory where the executable lives. If in doubt, try specifying the full path in ifstream inFile(...); to see whether that changes things.
Additionally, the file needs to have the correct permissions to ensure that it's readable by the process.
Changing a Linux C++ program which gives the user limited file access. Thus the program chroots itself to a sandbox with the files the user can get at. All worked well.
Now, however, the program needs to access some files for its own needs (not the user's) but they are outside the sandbox. I know chroot allows access to files opened before the chroot but in this case the needed files could a few among many hundreds so it is obviously impractical to open them all just for the couple that might be required.
Is there any way to get at the files?
Copy them into the sandbox or open them all before chrooting. Seriously. If there was a way to do this, there would be a way to suborn it to allow other access and make your protection useless.
The whole point of the sandbox is to prevent exactly what you're trying to achieve.
If the files are all in 1 directory, you could use mount to bind them to a directory inside the sandbox.
mount --bind /path/to/files /sandbox/files
The you can access the files through /sandbox/files/. If you don't want the user to see them, do mount --bind /path/to/files /sandbox/.files so the .files directory is hidden
I guess that you ought to be able to split your program into two parts, one which is chroot'ed and one which isn't, and have the chroot'ed portion request files' contents from the non-chroot'ed portion via the IPC mechanism of your choice.
This is a hack, and it may be easy to get wrong, negating any benefit of a chroot. Like paxdiablo says, you're trying to get around the whole purpose of a chroot sandbox, so your options are very, very limited.
Maybe if you explained a bit more what you're trying to accomplish, we might be able to offer some other ideas. For example, SELinux and AppArmor are more flexible than chroot and may be able to give you the security you seek.
If the files you need to access are within a few directories you could open those directories before you chroot and save the file descriptors. You can then use the so-called *at functions (e.g. openat(), renameat(), etc.) to get at the individual files. Basically you are opening the files relative to the already open directory file descriptors rather than the chrooted directory.
Whether this is a safe thing to do is open to question but it should work in Linux.
EDIT: This is on the ugly side but it seems to work. You should poke around a lot more for vulnerabilities than I have. I haven't tested how dropping privileges and so forth will effect things.
#include <iostream>
#include <string>
using namespace std;
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
if (argc < 4)
{
cerr << "USAGE: " << argv[0] << " <jail directory> <freeworld directory> <filename>\n";
exit(EXIT_FAILURE);
}
const string JAILDIR(argv[1]);
const string FREEDIR(argv[2]);
string freefilename(argv[3]);
while (freefilename[0] == '/')
freefilename.erase(0, 1);
DIR *pDir;
if ((pDir = opendir(FREEDIR.c_str())) == NULL)
{
perror("Could not open outside dir");
exit(EXIT_FAILURE);
}
int freeFD = dirfd(pDir);
//cd to jail dir
if (chdir(JAILDIR.c_str()) == -1)
{
perror("cd before chroot");
exit(EXIT_FAILURE);
}
//lock in jail
if (chroot(JAILDIR.c_str()) < 0)
{
cerr << "Failed to chroot to " << JAILDIR << " - " << strerror(errno) << endl;
exit(EXIT_FAILURE);
}
//
//in jail, won't work
//
string JailFile(FREEDIR);
JailFile += "/";
JailFile += freefilename;
int jailFD;
if ((jailFD = open(JailFile.c_str(), O_RDONLY)) == -1)
{
cout << "as expected, could not open " << JailFile << endl;
perror("exected open fail");
}
else
{
cout << "defying all logic, opened " << JailFile << endl;
exit(EXIT_FAILURE);
}
//
//using this works
//
if ((jailFD = openat(freeFD, freefilename.c_str(), O_RDONLY)) == -1)
{
cout << "example did not work. Could not open " << freefilename << " Sorry!" << endl;
exit(EXIT_FAILURE);
}
else
cout << "opened " << freefilename << " from inside jail" << endl;
char buff[255];
ssize_t numread;
while (1)
{
if ((numread = read(jailFD, buff, sizeof(buff) - 1)) == -1)
{
perror("read");
exit(EXIT_FAILURE);
}
if (numread == 0)
break;
buff[numread] = '\0';
cout << buff << endl;
}
return 0;
}
To test:
echo "Hello World" >/tmp/mystuff.dat
mkdir /tmp/jail
sudo ./myprog /tmp/jail /tmp mystuff.dat