Check for writing permissions to file in Windows/Linux - c++

I would like to know how to check if I have write permissions to a folder.
I'm writing a C++ project and I should print some data to a result.txt file, but I need to know if I have permissions or not.
Is the check different between Linux and Windows? Because my project should run on Linux and currently I'm working in Visual Studio.

The portable way to check permissions is to try to open the file and check if that succeeded. If not, and errno (from the header <cerrno> is set to the value EACCES [yes, with one S], then you did not have sufficient permissions. This should work on both Unix/Linux and Windows. Example for stdio:
FILE *fp = fopen("results.txt", "w");
if (fp == NULL) {
if (errno == EACCES)
cerr << "Permission denied" << endl;
else
cerr << "Something went wrong: " << strerror(errno) << endl;
}
Iostreams will work a bit differently. AFAIK, they do not guarantee to set errno on both platforms, or report more specific errors than just "failure".
As Jerry Coffin wrote, don't rely on separate access test functions since your program will be prone to race conditions and security holes.

About the only reasonable thing to do is try to create the file, and if it fails, tell the user there was a problem. Any attempt at testing ahead of time, and only trying to create the file if you'll be able to create and write to it is open to problems from race conditions (had permission when you checked, but it was removed by the time you tried to use it, or vice versa) and corner cases (e.g., you have permission to create a file in that directory, but attempting to write there will exceed your disk quota). The only way to know is to try...

The most correct way to actually test for file write permission is to attempt to write to the file. The reason for this is because different platforms expose write permissions in very different ways. Even worse, just because the operating system tells you that you can (or cannot) write to a file, it might actually be lying, for instance, on a unix system, the file modes might allow writing, but the file is on read only media, or conversely, the file might actually be a character device created by the kernel for the processes' own use, so even though its filemodes are set to all zeroes, the kernel allows that process (and only that process) to muck with it all it likes.

Similar to the accepted answer but using the non-deprecated fopen_s function as well as modern C++ and append open mode to avoid destroying the file contents:
bool is_file_writable(const std::filesystem::path &file_path)
{
FILE* file_handle;
errno_t file_open_error;
if ((file_open_error = fopen_s(&file_handle, file_path.string().c_str(), "a")) != 0)
{
return false;
}
fclose(file_handle);
return true;
}

Related

How to check if any files are open in a directory?

I am trying to delete all files in a folder, but if a file is left open, it will not delete. I need to check the folder for any open files, write their names to a text document, and then close the open files. As I don't have much experience, I am first trying to check one file in the same folder, then all in the same folder, then all in a different folder. I don't want to be to needy or demanding, so just some help with the first step would be nice.
I don't have a ton of experience coding, but I have tried using fstream and (name.is_open). I may be using them wrong, so I have not yet ruled them out.
// ifstream::is_open
#include <iostream> // std::cout
#include <fstream> // std::ifstream
void checkFiles() {
int done = 0;
while(done != 1){
std::cout << "Enter 0 for continue or 1 for done: ";
std::cin >> done;
std::ifstream ifs ("test.txt");
if (ifs.is_open()) {
// Print that file is open, then close
std::cout << "File is open\n";
std::ifstream.close():
}
else {
std::cout << "File not open\n";
}
}
For this bit of code, if the file is open, it should say "File is open."
If not, it should say "File not open"
Even if I force quit the .txt file, it still says that it is open.
Eventually, I want to have a new file that displays what files were open, as well as closing all the open files.
Standard C++ offers us the filesystem library to handle files and directories (standardized in C++17). However, checking which files are open is not - as far as I can tell - a feature of that library.
The is_open() method for std::fstream's is something completely different than what you're trying to check for: It tells you whether the particular stream object is in an open state (which would mean association with an open file) - and it doesn't use the OS to check which files are open. Typically, it's just a way to check whether you've closed it someplace else in your own program; at most, it might ensure that the OS has not unilaterally closed the OS-side file access handle. So, you won't get anywhere in that direction.
I also believe, though I'm not 100% certain, that Boost doesn't have a library which offers this capability, either. Boost's filesystem library is almost identical to std::filesystem, as the latter was based on it.
So, to the best of my knowledge, you either need to directly use operating-system-specific calls to do this, or look for a library offering this functionality, elsewhere.
If you haven't found anything else, you could track how this is currently done with what's available in userspace. There's a utility called lsof. It's available on some operating systems based on Linux, Darwin, FreeBSD and Solaris (e.g. available on MacOS). It's maintained here. The source code seems to be rather atrocious C. An intrepid developer could parse that mess, figure out what it does, extract the parts relevant for your specific use case, and refactor it into a reasonable, readable and short(ish) C++ function. I realize you (OP) might not be up for it at this point, but - maybe someone else reading this answer will get inspired to do it.
The pfiles command shows the open files for a process. You can run it for all or some processes.
However, Solaris (and UNIX) in general allows you to delete open files. The file can still be read and written while it is open (but deleted), but nobody else can open the same file and the file will be deleted when all processes have the file closed.

Raise I/O error while writing to an unreliable disk in C++

Imagine you have the following in C++:
ofstream myfile;
myfile.open (argv[1]);
if (myfile.is_open()){
for(int n=0;n<=10;n++){
myfile << "index="<<n<<endl;
sleep(1);
}
}else{
cerr << "Unable to open file";
}
myfile.close();
And while writing, the disk or medium you are writing to becomes unavailable but comes back on for the close() so that you have missing data in between. Or imagine you write to a USB flash drive and the device is withdrawn and re-inserted during the writing process.
How can you detect that ? I tried checking putting the write in try {} catch, flags(), rdstate(), you name it, but none thus far seem to work.
I don't think that is something you can detect at the stdio level. Typically when a hard drive temporarily stops responding, the operating system will automatically retry the commands either until they succeed or a timeout is reached, at which point your system call may receive an error. (OTOH it may not, because your call may have returned already, after the data was written into the in-memory filesystem cache but before any commands were sent to the actual disk)
If you really want to detect flakey hard drive, you'll probably need to code to a much lower level, e.g. write your own hardware driver.
IMHO you can try to:
Use ios:exceptions
Use low-level OS interactions
Verify that IO was successful (if 1 and 2 doesn't work)
I'm not sure if this will cover your scenario (removing a USB drive mid-write), but you can try enabling exceptions on the stream:
myfile.exceptions(ios::failbit | ios::badbit);
In my experience, iostreams do a "great" job of making it hard to detect errors and the type of error.
for(int n=0;n<=10;n++){
if (!(myfile << "index="<<n<<endl))
throw std::runtime_error("WRITE FAILED")
sleep(1);
}
If the std::ostream fails for any reason, it sets it's state bit, which is checked then the std::stream is in a boolean context. This is the same way you check if an std::istream read in data to a variable correctly.
However, this is the same as rdstate(), which you say you tried. If that's the case, the write has gotten to a buffer. endl, which flushes the programs buffer, shows that it's in the Operating System's buffer. From there, you'll have to use OS-specific calls to force it to flush the buffer.
[Edit] According to http://msdn.microsoft.com/en-us/library/17618685(v=VS.100).aspx, you can force a flush with _commit if you have a file descriptor. I can't find such a guarantee for std::ostreams.

Checking for file existence in C++

Currently I use something like:
#include <sys/stat.h>
#include "My_Class.h"
void My_Class::my_function(void)
{
std::ofstream my_file;
struct stat file_info;
if ( filename_str.compare("")!=0 &&
stat(filename_str.c_str(),&file_info) == 0 )
{
my_file.open(filename_str.data(),std::ios::trunc);
//do stuff
my_file.close();
}
else if ( filename_str.compare("")==0 )
{
std::cout << "ERROR! ... output filename not assigned!" << std::endl;
}
else
{
std::cout << "ERROR! File :" << std::endl
<< filename_str << std::endl
<< "does not exist!!" << std::endl;
}
}
...is this a decent way to go, or is there a better alternative? Seems like I could run amuck of permissions if I don't have permissions to read the file.
This is NOT a homework, question, it is a question about best practice.
I'd use the boost::filesystem constructs. Not only are they cross platform, they're part of the next standard library.
Generally I think it is best to just try opening it and catch an error.
IMO, checking permissions is unwise because what if it's a Linux box and you check its attributes, decide you can't write to it, but the filesystem supports ACL's and they do grant you permission? (As a sysadmin I can't stand when apps do this. I like ACL's and if you're an app, don't tell me you can't write to a file unless you've tried first.)
Conceptually, I'd say it depends on what you're planning to do with that file..
If you need its contents, go ahead and try to open it, and be prepared to handle failure gracefully, for the reasons Ken detailed.
If you are not currently interested in its contents (for example, when enumerating directory contents, or only planning to access a file at some point in the future, etc.), you might be better off just checking attributes for now. Otherwise, nasty things like hierarchical storage management may trigger an expensive (=slow) recall of file contents from, say, a tape backup or network (whereas attributes may have been cached). You could try to avoid that by checking for respective file attributes, but that's additional complexity, too.
So as a best practice, I'd suggest to open files sparingly (i.e., if you're not immediately interested in the contents, contend yourself with file attribute-based information), AND handle failure strictly in response to the actual call that opens the file when you need it.

Reading a stream in C++

I have the following code:
ifstream initFile;
initFile.open("D:\\InitTLM.csv");
if(initFile.is_open())
{
// Process file
}
The file is not opening. The file does exist on the D: drive. Is there a way to find out exactly why this file cannot be found? Like an "errno"?
You should be able to use your OS's underlying error reporting mechanism to get the reason (because the standard library is built on the OS primitives). The code won't be portable, but it should get you to the bottom of your issue.
Since you appear to be using Windows, you would use GetLastError to get the raw code and FormatMessage to convert it to a textual description.
Answered here I believe: Get std::fstream failure error messages and/or exceptions
The STL is not great at reporting errors. Here's the best you can do within the standard:
ifstream initFile;
initFile.exceptions(ifstream::eofbit|ifstream::failbit|ifstream::badbit);
try
{
initFile.open("D:\\InitTLM.csv");
// Process File
}
catch(ifstream::failure e)
{
cout << "Exception opening file:" << e.what() << endl;
}
In my experience, the message returned by what() is usually useless.
Check the permissions on the root of the D: drive. You may find that your compiled executable, or the service under which your debugger is running, does not have sufficient access privileges to open that file.
Try changing the permissions on the D:\ root directory temporarily to "Everyone --> Full Control", and see if that fixes the issue.

How to check if a file has been opened by another application in C++?

I know, that there's the is_open() function in C++, but I want one program to check if a file hasn't been opened by another application. Is there any way to do it using standard library?
EDIT - Clarified in the answers that this is for a Linux application.
Not only the standard library does not have this funcionality, it's not even possible in general. You could (on linux) check /proc/*/fd — but it is possible that your program does not have permission to do it on processes from other users (this is the default in Ubuntu, for instance).
No, the standard library has no such functionality.
If you control the other process (have source code), the best plan is to use advisory locks in both processes. This locking is defined in POSIX, and will be portable across operating systems.
In Linux, you can use the utility lsof to see what files are opened by other processes.
This is limited to what you have permissions for - you have to do the check as a privileged user, or you'll only get results for files opened by the same user as the one doing the check.
I only know of the command line utility, not of any system call you can use directly from C code.
In Linux, it's also possible to turn on mandatory locking for a given filesystem (mount -o mand), and set special flags on the file (chmod g-x,g+s). Then when your process attempts to acquire a write lock, it will fail if another process has the file open. This is hardly ever used, but if you completely control the system in question, it may be an option.
The following code may work.
int main(int argc, char ** argv)
{
int fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
}
if (fcntl(fd, F_SETLEASE, F_WRLCK) && EAGAIN == errno) {
puts("file has been opened");
}
else {
fcntl(fd, F_SETLEASE, F_UNLCK);
puts("file has not been opened");
}
close(fd);
return 0;
}
Perhaps you could just try and get a full write lock? It'll fail if anyone else has it open for reading or writing.
fopen("myfile.txt", "r+")
If it's not cross platform and is Win32, then you can request even more fine-grained set of locks.
See here
and look at dwShareMode, value of 0, as well as the other parameters.
Nope. Unless other application uses advisory locks.
See http://docs.sun.com/app/docs/doc/816-0213/6m6ne37v5?a=view
Non-natively, you could call out to Sysinternals' handle.exe as a last resort...
As #Neil Butterworth says, the standard library doesnt.
In unix you can use fcntl to use file locks.
You could write a wrapper for your open function, that checks for a lock (and locks if none exists) a file if its open by no one else. You shold write a wrapper for close as well, that releases that lock on file close.
Seeing you have tagged linux -> there's a command-line too and API that have been added to the Linux kernel and do just that: inotify.
Here's the man page.
In Windows this little and dirty trick will work (if the file exists and you have the right permissions)
if ( 0 != rename("c:/foo.txt", "c:/foo.txt") ) {
printf("already opened\n");
}
It's likely to work also in Linux.