how to check if the file is closed - c

I have file descriptor and inside my signal handler, i close the file. But due to other conditions, the file could have been closed earlier. Is there a way to check if the file descriptor points to an open file in c and linux?
UPDATE:
Is it possible to determine filename associated with a file descriptor? This way if the fd gets recycled, app can detect it.

Try to do any file operation like lseek on the file descriptor. If it returns -1. Then check errno, if its EBADF then the file descriptor is already closed.
Try to do lseek in an unaffected manner like below.
lseek(fd, 0, SEEK_CUR);
Usually while opening the first file in a program we always get the file descriptor as 3. After this file is closed, if we try to open some other file we will get the same file descriptor as 3. Because always we will get the lowest available number. If we are closing and reopening many files in a program, then we need to improve our code to track of file descriptors list to check whether its closed or not.

When you open a file, it always get the minimal available fd assigned. So if you close your fd, and then open another file somewhere in your code, you could easily have the same fd reassigned to this new file. So there is no reliable way to tell that the file descriptor is closed, because it can now point to another opened file.

After you closed the file descriptor fd assign -1 to it, so you later could test fd against -1 to see if you already closed it.
You could lookup the filename a (valid) file descriptor referrs to by calling readlink() on /proc/<pid>/fd/<file descriptor>.

Related

Can I close a FILE without closing the fd?

I've opened a FILE *f with fdopen(fd, "w+") and I would like to keep the fd open after closing with fclose(f).
Is there an elegant way to do that?
Can I simply call fflush(f); free(f); or is that dangerous?
Or is there a way to change the internal fd to an invalid value -1 so that fd cannot be closed by fclose()?
If you want to get the file descriptor and disassociate it from the the FILE*, there is one supported way:
Get the file descriptor with fileno(). (POSIX)
Duplicate it using dup(). (POSIX)
Close the FILE the normal way with fclose(). (c)
Now you only have a file descriptor.
If you'd really like to use a FILE object rather than a file descriptor, you needn't worry about close()ing the file descriptor: fclose() does this for you. Also, if performance is important, you should worry about all of the fdopen() and wrapped system calls defined in f*() standard I/O functions. Big thanks to all the comments!
Also see the fclose man page:
The fclose() function flushes the stream pointed to by fp (writing any buffered output data using fflush(3)) and closes the underlying file descriptor.

What are the rules of closing file descriptors after calling dup/dup2?

I feel like this is a topic I've taken for granted. In the past I literally just closed as many file descriptors "because I was told to". Most of the time this worked, but occasionally I ran into some unpredictable behaviour.
Thus, I'd like to ask - what the rule for closing file descriptors after calling dup / dup2?
Let's say I want to perform cat < in > out.
fd[IN] = open("in", O_RDONLY);
saved_stdin = dup(STDIN_FILENO);
dup2(fd[IN], STDIN_FILENO);
close(fd[IN])
fd[OUT] = open("out", O_WRONLY | O_CREAT | O_TRUNC, 0644);
saved_stdout = dup(STDOUT_FILENO);
dup2(fd[OUT], STDOUT_FILENO);
close(fd[OUT])
// Later on when I want to restore stdin and stdout
dup2(saved_stdin, STDIN_FILENO);
close(saved_stdin);
dup2(saved_stdout, STDINOUT_FILENO);
close(saved_stdout);
Is this correct or should I be closing more file descriptors?
The rule is indeed quite simple. For both dup() variants, it is true, that:
The source fd remains open and will have to be closed once it is no longer needed.
The target file descriptor,
when using dup(), is always an unused one
when using dup2(), is implicitly closed and replaced by a copy of the source fd.
The new target fd has to be closed, when it is no longer needed.
Source fd refers to the file descriptor to be duplicated, while target fd is the new file descriptor.
int new_fd = dup(source_fd);
dup2(source_fd, new_fd);
So yes, your code does the necessary closes, and no unneeded ones.
The figures is come from CSAPP System-Level:
Figure 2: Before Redirect IO
dup2(4,1);
Figure 1: After Redirect IO
Notice the refcnt of fd 1 has changed to 0, after call dup2.
According to the description of close in linux manual. It said:
if the file descriptor was the last reference to a file which has been removed using unlink(2), the file is deleted.
close be used to decrease the refcnt of opened file. we use dup to create a new fd will increase the refcnt of opened file. when we call close function, it did't close the file immediately, it only decrease the reference count of file. the file will be close/delete when the refcnt is 0.
So it's really like the Reference counting for memory management.

Closing and reopening piped file descriptors for writing in c

I have a question please regarding what happens if I closed a file descriptor after writing into it ( e.g fd[1] after piping fd ), then opened it again to write. Will the data be overwritten and all the previous ones will be gone or it will keep on writing from the end point it stopped at after the first write?
I used the system call open() with the file descriptor and no other arguments.
If you close either of the file descriptors for a pipe, it can never be reopened. There is no name by which to reopen it. Even with /dev/fd file systems, once you close the file descriptor, the corresponding entry in the file system is removed — you're snookered.
Don't close a pipe if you might need to use it again.
Consider whether to make a duplicate of the pipe before closing; you can then either use the duplicate directly or duplicate the duplicate back to the original (pipe) file descriptor, but that's cheating; you didn't actually close all the references to the pipe's file descriptor. (Note that the process(es) at the other end of the pipe won't get an EOF indication because of the close — there's still an open file descriptor referring to the pipe.)

How to check if a file still exists using a file descriptor

I have a file descriptor that is set to a positive value with the result of a open() function so this fd is indicating a file. When i delete the actual file fd is still a positive integer. I want to know that if i delete a file for some reason, how can i know that this file descriptor is not valid anymore. In short, how can i know that the file that fd is indicating, still there or not. I am trying to do this in C on FreeBSD.
Unix systems let you delete open files (or rather, delete all references to the file from the filesystem). But the file descriptor is still valid. Any read and write calls will be successful, as they would with the filename still there.
In other words, you cannot fully delete a file until the file descriptor is closed. Once closed, the file will then be removed automatically.
With a valid file descriptor, you can check if the filename still exists, e.g.
printf("%d\n", buf.st_nlink); // 0 means no filenames
Where buf is a struct stat initialised with fstat.
Before writing to the file you could check if it is still there using access()
if (access("/yourfile",W_OK)!=-1) {
//Write on the file
}
You can also do fstat on the descriptor:
struct stat statbuf;
fstat(fd,&statbuf);
if (statbuf.st_nlink > 0) {
//File still exists
}
But it will slow your software down a lot, and also some program could link the file somewhere else and unlink the original name, so that the file would still be existing but under a different name/location, and this method would not detect that.
A much better alternative would be to use inotify on GNU/Linux, or kqueue on bsd, but I've never used the 2nd one.
You can use these API to watch changes in directories and get notifications from the kernel and get an event when your file is being deleted by some other process, and do something about it.
Keep in mind that this events are not in real time, so you could still use the file for a couple of milliseconds before getting the event.

How to re-open a closed file descriptor

I have a scenario where i created pipe for communication between two child and parent. Parent writes (using write function)data to the pipe and closes the respective file descriptor. The problem is when i want to write data again to the pipe, the write function is returning error code -1. I think its because writing end has been closed in previous iteration. Then how to open the corresponding file descriptor after it has been closed once.
I tried using open() function which requires path to some file as arguement. But i am not using any files in my application. I have simple file descriptors (int arr[2]).
Is it possible to achieve above scenario with pipes????
Once a pipe is closed, it's closed. You can't bring it back.
If you want to write more to it, don't close it in the first place - it's as simple as that.
Thing to know about anything related to files (pipes are also some sort of files) under unix: file name is used only on opening file. Later until file is open, it is available forever until closed and name is never used again. When someone deletes file in another window while it is open, just name is gone, not file. This means:
File is still on disk
It has no name
It is still open
When it is closed, kernel removes it forever
Knowing this maybe helps to understand, why this would be nearly impossible to "reopen" file, pipe or anything similar again. File name and descriptor have different lifetimes.
The only exceptions are stdout and stderr whose descriptor are always known as 1 and 2.

Resources