C++: File open call fails - c++

I have the following code in one of my library functions that I am calling many times in a loop. After a large number of iterations I find that open returns -1 which it shouldn't have as the previous iterations worked fine. What may be the cause. How can I get more details on the error.?
int mode;
if (fileLen == 0)
mode = O_TRUNC | O_RDWR | O_CREAT;
else
mode = O_RDWR;
myFilDes = open (fName, mode, S_IRUSR | S_IWUSR);
EDIT:After the end of each iteration I am calling a method that library exposes which internally calls close (myFilDes);

perror is the standard function to map errno to string and print it out to stderr:
if (myFilDes == -1)
perror("Unable to open file: ");
man errno / man perror / man strerror for more info.

Are you closing these handles as well? Do you reach a specific number of open calls before it starts failing?
The errno variable should have additional information as to what the failure is. See: http://linux.die.net/man/2/open

Related

How to make open() truncate an existing file

I m opening a file with open() function.
I want that open() function discard the file content if it already exists, and then the file is treated as a new empty file.
I tried with the following code:
int open_file(char *filename)
{
int fd = -1;
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) {
printf("Couldn't create new file %s: %s\n",
filename, strerror(errno));
return -1;
}
close(fd);
return 0;
}
but I got the following error:
Couldn't create new file kallel333: File exists
What am I missing?
Please add O_TRUNC flag and remove O_EXCL.
open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
From open man page -
O_EXCL Ensure that this call creates the file: if this flag is
specified in conjunction with O_CREAT, and pathname already
exists, then open() will fail.
O_TRUNC
If the file already exists and is a regular file and the
access mode allows writing (i.e., is O_RDWR or O_WRONLY) it
will be truncated to length
The problem is the O_EXCL flag. From the man page for open(2):
O_EXCL Ensure that this call creates the file: if this flag is specified in conjunction with O_CREAT, and pathname already exists, then open() will fail.
I suggest removing O_EXCL, adding O_TRUNC, and trying again.
The manual page for open() says this about the O_TRUNC flag:
O_TRUNC
If the file already exists and is a regular file and the open mode allows writing (i.e., is O_RDWR or O_WRONLY) it will be truncated to length 0. If the file is a FIFO or terminal device file, the O_TRUNC flag is
ignored. Otherwise the effect of O_TRUNC is unspecified.
As everyone has stated, it's due to using the O_EXCL flag, when it should be the O_TRUNC flag instead. I just had this same issue. My best advice to anyone trying to use these syscalls that involve macros is to read the man page of your syscall. Understand what your macros mean before you try to use them and confuse yourself.
man 2 open
I will tell you what this error is all about ! Open function will have a return type i.e some value will be returned after the execution of this system call (which in your case will be stored in fd). This value will indicate whether the execution of the system call is a success or not. When open system call fails, it automatically returns -1 (to fd) which you are already initializing in the first statement of your function int fd = -1;. Therefore, the statement if (fd < 0) is being validated as correct and hence you are getting that error. Please note that you should not set the return values of the system calls, they are to be returned automatically when the program executes. What you need to do is just make sure you capture that value and validate it. So please change your first statement of the function int fd = -1 to simply int fd.
Bottom line: You are setting the return value of the open system call to -1 thereby telling the compiler that its creation should fail at any cost !! As far as the permissions are concerned, please refer to the other comments !! :)

Opening pipe in append mode

I'm trying to open a fifo pipe, into which one thread writes, the synchronization is all good.
However, for understandable reasons I need it to be opened in append mode.
When I open it as follow:
ret_val = mkfifo(lpipename.c_str(), 0666);
if((pipehandler = open(lpipename.c_str(), O_RDWR)) < 1)
{
perror("Failed to open pipe file");
syslog(LOG_ERR, "Failed to open pipe file");
exit(1);
}
I don't have any problems and I can see the pipe marked in yellow when 'ls'-ing my folder
But when I try to open the pipe as follows, in append mode:
ret_val = mkfifo(lpipename.c_str(), 0666);
if((pipehandler = open(lpipename.c_str(), O_RDWR| O_APPEND)) < 1)
{
perror("Failed to open pipe file");
syslog(LOG_ERR, "Failed to open pipe file");
exit(1);
}
I can't see the pipe in folder at all.
For the record, I get an error in NEITHER one of the options
Does anyone have any idea of why?
Thanks
O_APPEND may lead to corrupted files on NFS file systems if more than one process appends data to a file at once. This is because NFS does not support appending to a file, so the client kernel has to simulate it, which can't be done without a race condition.
It may be due to this,for more details look into the below link
http://www.kernel.org/doc/man-pages/online/pages/man2/open.2.html
It's a FIFO. How could it do anything else but append? I believe appending is the norm, thus it will always append no matter how you open it.

File open issues

What would be the reason that this code result in an m_cause of 0 for a file open. Found plenty of reasons that another code will be returned but no reasons for 0.
CFileException fileException;
CFile myFile;
if (myFile.Open("C:\\test\\docs\\test.txt", CFile::modeCreate | CFile::modeWrite, &fileException))
{
TRACE( "Can't open file %s, error = %u\n", "test.txt", fileException.m_cause );
}
CFile::Open() returns none zero upon success, the call in your example does not fail!
Check for !CFile::Open(...)
Return value
Nonzero if the open was successful; otherwise 0. The pError parameter is meaningful only if 0 is returned.
Taken from MSDN (I've linked to the documentation for Visual Studio 2010, but it's the same going back as far as VS2005 and 2003, and probably beyond that).
As per bert-jan's suggestion, you should check for !CFile::Open(...) as in the event that the file does fail to open, you won't actually handle the error.

exec family with a file input

Hey guys I am trying to write a shell with C++ and I am having trouble with the function of using input file with the exec commands. For example, the bc shell in Linux is able to do “bc < text.txt” which calculate the lines in the text in a batch like fashion. I am trying to do likewise with my shell. Something along the lines of:
char* input = “input.txt”;
execlp(input, bc, …..) // I don’t really know how to call the execlp command and all the doc and search have been kind of cryptic for someone just starting out.
Is this even possible with the exec commands? Or will I have to read in line by line and run the exec commands in a for loop??
You can open the file and then dup2() the file descriptor to standard input, or you can close standard input and then open the file (which works because standard input is descriptor 0 and open() returns the lowest numbered available descriptor).
const char *input = "input.txt";
int fd = open(input, O_RDONLY);
if (fd < 0)
throw "could not open file";
if (dup2(fd, 0) != 0) // Testing that the file descriptor is 0
throw "could not dup2";
close(fd); // You don't want two copies of the file descriptor
execvp(command[0], &command[0]);
fprintf(stderr, "failed to execvp %s\n", command[0]);
exit(1);
You would probably want cleverer error handling than the throw, not least because this is the child process and it is the parent that needs to know. But the throw sites mark points where errors are handled.
Note the close().
the redirect is being performed by the shell -- it's not an argument to bc. You can invoke bash (the equivalent of bash -c "bc < text.txt")
For example, you can use execvp with a file argument of "bash" and argument list
"bash"
"-c"
"bc < text.txt"

DeleteFile fails on recently closed file

I have a single threaded program (C++, Win32, NTFS) which first creates a quite long temporary file, closes it, opens for read, reads, closes again and tries to delete using DeleteFile().
Usually it goes smoothly, but sometimes DeleteFile() fails, and GetLastError() returns ERROR_ACCESS_DENIED. File is not read-only for sure. It happens on files on any size, but the probability grows with the file size.
Any ideas what may be locking the file? I tried WinInternals tools to check and found nothing suspicious.
Windows is notorious for this issue. SQLite handles the problem by retrying the delete operation every 100 milliseconds up to a maximum number.
I believe if you are sure that you have no open handles, doing this in your implementation will save you some headaches when things like antivirus software open the file.
For reference, the comment from SQLite source:
/*
** Delete the named file.
**
** Note that windows does not allow a file to be deleted if some other
** process has it open. Sometimes a virus scanner or indexing program
** will open a journal file shortly after it is created in order to do
** whatever it does. While this other process is holding the
** file open, we will be unable to delete it. To work around this
** problem, we delay 100 milliseconds and try to delete again. Up
** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
** up and returning an error.
*/
Just a wild guess - do you have any anti-virus software installed? Have you tried disabling any real-time protection features in it, if you do?
I believe this is covered in Windows Internals. The short story is that even though you've called CloseHandle on the file handle, the kernel may still have outstanding references that take a few milliseconds to close.
A more reliable way to delete the file when you're done is to use the FILE_FLAG_DELETE_ON_CLOSE flag when opening the last handle. This works even better if you can avoid closing the file between reads/writes.
#include <windows.h>
#include <stdio.h>
int wmain(int argc, wchar_t** argv)
{
LPCWSTR fileName = L"c:\\temp\\test1234.bin";
HANDLE h1 = CreateFileW(
fileName,
GENERIC_WRITE,
// make sure the next call to CreateFile can succeed if this handle hasn't been closed yet
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
CREATE_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN | FILE_ATTRIBUTE_TEMPORARY,
NULL);
if (h1 == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "h1 failed: 0x%x\n", GetLastError());
return GetLastError();
}
HANDLE h2 = CreateFileW(
fileName,
GENERIC_READ,
// FILE_SHARE_WRITE is required in case h1 with GENERIC_WRITE access is still open
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
// tell the OS to delete the file as soon as it is closed, no DeleteFile call needed
FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_SEQUENTIAL_SCAN | FILE_ATTRIBUTE_TEMPORARY,
NULL);
if (h2 == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "h2 failed: 0x%x\n", GetLastError());
return GetLastError();
}
return 0;
}
Add a MessageBox() call before you invoke DeleteFile(), When it shows up, run the sysinternals tool Process Explorer.
Search for an open handle to the file. In all probability you have not closed all handles to the file...
Maybe the changes are still cached and haven't been saved yet?
You can check this by adding a WaitForSingleObject on the file handle to be sure.
You may have a race condition.
1. Operating system is requested to write data.
2. Operating system is requested to close file. This prompts final buffer flushing. The file will not be closed until the buffer flushing is done. Meanwhile The OS will return control to the program while working on buffer flushing.
3. Operating system is requested to delete the file. If the flushing is not done yet then the file will still be open and the request rejected.
#include <iostream>
#include <windows.h>
int main(int argc, const char * argv[])
{
// Get a pointer to the file name/path
const char * pFileToDelete = "h:\\myfile.txt";
bool RemoveDirectory("h:\\myfile.txt");
// try deleting it using DeleteFile
if(DeleteFile(pFileToDelete ))
{
// succeeded
std::cout << "Deleted file" << std::endl;
}
else
{
// failed
std::cout << "Failed to delete the file" << std::endl;
}
std::cin.get();
return 0;
}