C++/boost: checking process permission - c++

I'm writting a C++ program in order to make some static analyse and modifications over a website. I don't change the project files, but the files are copied, analysed and modified in a new folder.
Is there a way of checking, for example, using boost::filesystem, if I (the program/the user executing it) have permissions enough to read (files), execute (for processing the directory hierarchy) and write (files or create new folders) on a current folder and its files (or at least under unix systems)?

No, you can not check file permissions with boost program options library. File permissions can be queried with boost filesystem library:
#include <boost/filesystem.hpp>
#include <stdio.h>
namespace bfs=boost::filesystem;
int main(int argc,char * argv[])
{
if (argc < 2)
return;
bfs::path p(argv[1]);
bfs::file_status s = status(p);
printf("%X\n",s.permissions());
}
The values of permissions flags are as enum perms in
boost/filesystem/v3/operations.hpp

IF you're using linux you can use stat function for get info about the file, including the mode permissions, the owner's ID and the owner's group ID of such file.
Then you can use getuid to compare the permissions of the user running the program with those obtained with stat.
Both links (that are actually man pages) has examples on how to use these functions.
Also you can try to do some operation over the selected file, lets say write, and then handle the exception properly. You don't have to access the file, just try to open it for writting, if you get and exception and errno is equal to EACCESS(permission denied) well, you don't have shuch permissions.

Related

Setting permissions to a directory using C++

I try to create new directory and set its permissions (using at most c++11 and without boost) so user, group and others can list files inside read them and write new files (linux environment).
#include <sys/stat.h>
#include <sys/types.h>
int main(void) {
const char* path = "/tmp/newDir";
mode_t process_mask = umask(0);
int syscall_status = mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
umask(process_mask);
return syscall_status;
}
This code is based on the man (2) page of mkdir (and umask).
However the created directory has rwxr-xr-x permissions (no write for group and others).
I also tried using chmod syscall on the directory but it didn't solve the problem. Other sources in stackoverflow treated files (rather than folders), and trying to apply the file-methods on my directory didn't work as well.
Also, I want to avoid calling system() from stdlib, this is the last option I'll use if I don't find a solution (security considerations).
char* path = "/tmp/newDir";
Besides the syntax error, this is ill-formed since C++11. Prior to that, this would be using a deprecated conversion. String literals are const in C++ -> Use pointer to const.
Other than that, the program is correct assuming a POSIX system. If it fails, then you can check errno to see why. If you don't get all permissions: Check if the parent directory has a default ACL; that would override umask.
A portable way of creating a directory in C++ is std::filesystem::create_directory and a way of setting permissions is std::filesystem::permissions.

Does QFile::copy keep the source file permissions in the copied file?

I am trying to copy a game from a disk or USB flash drive to hard drive in my computer using Qt and I wanted to use QFile::copy and it is important for me to keep the permissions like being executable and writable.
Do I have to use QFile::setPermissions or the permissions are not changed by default in the copy function call?
QFile::copy preserves the file permissions, as evidenced by the source code:
if(!error) {
QFile::setPermissions(newName, permissions());
close();
unsetError();
return true;
}
QFile::setPermissions(newName, permissions()); actually copies the permissions from the current file to the file named newName. Hence, there is no need to do that manually.

Setting file permissions when opening a file with ofstream

Is there a way in C++'s standard libraries (or linux sys/stat.h, sys/types.h, sys/.... libraries) to set the file permissions of a file when creating it with ofstream (or using something else from those libraries)?
When I create a file it just gets created with some default set of file permissions (I assume whatever the current umask is), but I want to explicitly set the permissions to something other than the default (ex. 600), and I can't just set the umask before starting the program (b/c others will run it).
// Example of creating a file by writing to it
ofstream fp(filename.c_str())
/* write something to it */
Is there a way to do this in C++ or if not, a way to set the umask within the C++ program?
For example, in C's standard library you can just do:
open(filename, O_RDWR|O_CREAT, 0666)
but I don't want to resort to using the C function, as it'd be nice to be able to use the functions associated with fstream objects.
(Side Note: there was a question whose title was exactly what I was looking for, but it turned out to be unrelated.)
You cannot. The standard library must be platform agnostic, and permissions like 0600 are meaningless on Windows for example. If you want to use platform-specific features, you'll need to use platform-specific APIs. Of course, you can always call umask() before you open the file, but that's not part of the C++ standard library, it's part of the platform API.
Note: open() isn't part of the C standard library either. It's a platform API. The C standard library function to open a file is fopen().
In C++17, std::filesystem::permissions was introduced. It will enable you to get and set permissions in a platform-agnostic manner.
Get permissions:
using fs = std::filesystem;
bool owner_can_read =
fs::status("my_file.txt").permissions() & fs::perms::owner_read != fs::perms::none;
Set permissions (add all permissions for owner and group, that is, add modes 0x770 on unix):
using fs = std::filesystem;
fs::permissions("my_file.txt",
fs::perms::owner_all | fs::perms::group_all,
fs::perm_options::add);
Example based on an example from cppreference.

Write a file in a specific path in C++

I have this code that writes successfully a file:
ofstream outfile (path);
outfile.write(buffer,size);
outfile.flush();
outfile.close();
buffer and size are ok in the rest of code.
How is possible put the file in a specific path?
Specify the full path in the constructor of the stream, this can be an absolute path or a relative path. (relative to where the program is run from)
The streams destructor closes the file for you at the end of the function where the object was created(since ofstream is a class).
Explicit closes are a good practice when you want to reuse the same file descriptor for another file. If this is not needed, you can let the destructor do it's job.
#include <fstream>
#include <string>
int main()
{
const char *path="/home/user/file.txt";
std::ofstream file(path); //open in constructor
std::string data("data to write to file");
file << data;
}//file destructor
Note you can use std::string in the file constructor in C++11 and is preferred to a const char* in most cases.
Rationale for posting another answer
I'm posting because none of the other answers cover the problem space.
The answer to your question depends on how you get the path. If you are building the path entirely within your application then see the answer from #James Kanze. However, if you are reading the path or components of the path from the environment in which your program is running (e.g. environment variable, command-line, config files etc..) then the solution is different. In order to understand why, we need to define what a path is.
Quick overview of paths
On the operating systems (that I am aware of), a path is a string which conforms to a mini-language specified by the operating-system and file-system (system for short). Paths can be supplied to IO functions on a given system in order to access some resource. For example here are some paths that you might encounter on Windows:
\file.txt
\\bob\admin$\file.txt
C:..\file.txt
\\?\C:\file.txt
.././file.txt
\\.\PhysicalDisk1\bob.txt
\\;WebDavRedirector\bob.com\xyz
C:\PROGRA~1\bob.txt
.\A:B
Solving the problem via path manipulation
Imagine the following scenario: your program supports a command line argument, --output-path=<path>, which allows users to supply a path into which your program should create output files. A solution for creating files in the specified directory would be:
Parse the user specified path based on the mini-language for the system you are operating in.
Build a new path in the mini-language which specifies the correct location to write the file using the filename and the information you parsed in step 1.
Open the file using the path generated in step 2.
An example of doing this:
On Linux, say the user has specified --output-path=/dir1/dir2
Parse this mini-language:
/dir1/dir2
--> "/" root
--> "dir1" directory under root
--> "/" path seperator
--> "dir2" directory under dir1
Then when we want to output a file in the specified directory we build a new path. For example, if we want to output a file called bob.txt, we can build the following path:
/dir1/dir2/bob.txt
--> "/" root
--> "dir1" directory under root
--> "/" path separator
--> "dir2" directory under dir1
--> "/" path seperator
--> "bob.txt" file in directory dir2
We can then use this new path to create the file.
In general it is impossible to implement this solution fully. Even if you could write code that could successfully decode all path mini-languages in existence and correctly represent the information about each system so that a new path could be built correctly - in the future your program may be built or run on new systems which have new path mini-languages that your program cannot handle. Therefore, we need to use a careful strategy for managing paths.
Path handling strategies
1. Avoid path manipulation entirely
Do not attempt to manipulate paths that are input to your program. You should pass these strings directly to api functions that can handle them correctly. This means that you need to use OS specific api's directly avoiding the C++ file IO abstractions (or you need to be absolutely sure how these abstractions are implemented on each OS). Make sure to design the interface to your program carefully to avoid a situation where you might be forced into manipulating paths. Try to implement the algorithms for your program to similarly avoid the need to manipulate paths. Document the api functions that your program uses on each OS to the user - this is because OS api functions themselves become deprecated over time so in future your program might not be compatible with all possible paths even if you are careful to avoid path manipulation.
2. Document the functions your program uses to manipulate paths
Document to the user exactly how paths will be manipulated. Then make it clear that it is the users responsibility to specify paths that will work correctly with the documented program behavior.
3. Only support a restricted set of paths
Restrict the path mini-languages your program will accept until you are confident that you can correctly manipulate the subset of paths that meet this set of restrictions. Document this to the user. Error if paths are input that do not conform.
4. Ignore the issues
Do some basic path manipulation without worrying too much. Accept that your program will exhibit undefined behavior for some paths that are input. You could document to the user that the program may or may not work when they input paths to it, and that it is the users responsibly to ensure that the program has handled the input paths correctly. However, you could also not document anything. Users will commonly expect that your program will not handle some paths correctly (many don't) and therefore will cope well even without documentation.
Closing thoughts
It is important to decide on an effective strategy for working with paths early on in the life-cycle of your program. If you have to change how paths are handled later it may be difficult to avoid a change in behaviour that might break the your program for existing users.
Try this:
ofstream outfile;
string createFile = "";
string path="/FULL_PATH";
createFile = path.as<string>() + "/" + "SAMPLE_FILENAME" + ".txt";
outfile.open(createFile.c_str());
outfile.close();
//It works like a charm.
That needs to be done when you open the file, see std::ofstream constructor or open() member.
It's not too clear what you're asking; if I understand correctly, you're
given a filename, and you want to create the file in a specific
directory. If that's the case, all that's necessary is to specify the
complet path to the constructor of ofstream. You can use string
concatenation to build up this path, but I'd strongly recommend
boost::filesystem::path. It has all of the functions to do this
portably, and a lot more; otherwise, you'll not be portable (without a
lot of effort), and even simple operations on the filename will require
considerable thought.
I was stuck on this for a while and have since figured it out. The path is based off where your executable is and varies a little. For this example assume you do a ls while in your executable directory and see:
myprogram.out Saves
Where Saves is a folder and myprogram.out is the program you are running.
In your code, if you are converting chars to a c_str() in a manner like this:
string file;
getline(cin, file, '\n');
ifstream thefile;
thefile.open( ("Saves/" + file + ".txt").c_str() );
and the user types in savefile, it would be
"Saves/savefile.txt"
which will work to get to to get to savefile.txt in your Saves folder. Notice there is no pre-slashes and you just start with the folder name.
However if you are using a string literal like
ifstream thefile;
thefile.open("./Saves/savefile.txt");
it would be like this to get to the same folder:
"./Saves/savefile.txt"
Notice you start with a ./ in front of the foldername.
If you are using linux, try execl(), with the command mv.

Lock / Prevent edit of source files on Linux using C++

How can I programmatically lock/unlock, or otherwise prevent/enable editing, a source file on Linux using C++.
I want to be able to lock source file so that if I open it in an editor it will not allow me to save back to the same source file.
I am thinking of maybe changing the permissions to read-only (and change it back to read-write later): how do I do that from C++?
Try man fchmod:
NAME
chmod, fchmod - change permissions of a file
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fildes, mode_t mode);
Why aren't you using a source code management tool like CVS or Subversion? CVS does nice locking (so does Subversion). More importantly, you have the history of changes. Better still (with CVS anyway) you have to make the step of doing a "checkout" to make the file writeable.
Yes, it is a bit hard to tell what you are looking for
Security against other users editing you files -> use "chmod, fchmod"
Security against you yourself accidentally messing with your source files -> you should really change your thinking and use a source control tool. Like Subversion (SVN) or even better Mercurial.