linux function openat vs open, what does "at" mean? - c

I know how to use the two functions, but I do not know what the suffix "at" means. Does it represent the abbreviation of "another"?

At means that the working directory considered for the open call is at the given file descriptor, passed as the parameter. The *at() family of functions are useful so that all path relative operations refer to the same file inode, even if it changes name or someone replaces it.

Related

fopen() function with a dynamic location in C

I just want to learn that how can I open a file with fopen() function from a dynamic location. I mean, for example it will be a system file and in another computer, this file can be in another location. So if I will set my location in my code not dynamically, my program will not work in another computer. So how Can I set the location dynamically for my program will find this file wherever it is?
You can (and often should) pass program arguments to your main, thru the conventional int argc, char**argv formal arguments of your main. See also this.
(I am focusing on Linux, but you could adapt my answer to other OSes and platforms)
So you would use some convention to pass that file path (not a location, that word usually refers to memory addresses) to your program (often thru the command line starting your program). See also this answer.
You could use (at least on Linux) getopt_long(3) to parse program arguments. But there are other ways, and you can process the arguments of main explicitly.
You could also use some environment variable to pass that information. You'll query it with getenv(3). Read also environ(7).
Many programs have configuration files (whose path is wired into the program but often can be given by program arguments or by environment variables) and are parsing them to find relevant file paths.
And you could even consider some other inter-process communication to pass a file path to your program. After all, a file path is just some string (with restrictions and interpretations explained in path_resolution(7)). There are many ways to pass some data to a program.
Read also about globbing, notably glob(7). On Unix, the shell is expanding the program arguments. You may want to use functions like glob(3) or wordexp(3) on something obtained elsewhere (e.g. in some configuration file) to get similar expansion.
BTW, be sure, when using fopen, to check against its failure. You'll probably use perror like here.
Look also into the source code of several free software projects (perhaps on github) for inspiration.
I would suggest you to use the environment variables, In a PC set your file location as environment variable. then read the environment variable value in your program, then open the file. This idea works both in linux and windows however you have adopt the code based on the OS to read the environment variables.
Besides specifying file location at runtime through command line arguments, environment variables or configuration files, you can implement a PATH-like logic:
Possible locations for your file are set in an environment variable:
export MY_FILE_PATH=/usr/bin:/bin:/opt/bin:$HOME/bin
Your program reads that environment variable, parses its contents and checks existence of file in each specified path, with fopen() return status.

Is the remove function guaranteed to delete the file?

The wording of the C99 standard seems a bit ambiguous regarding the behavior of the remove function.
In section 7.19.4.1 paragraph 2:
The remove function causes the file whose name is the string pointed to by filename
to be no longer accessible by that name. A subsequent attempt to open that file using that
name will fail, unless it is created anew.
Does the C99 standard guarantee that the remove function will delete the file on the filesystem, or could an implementation simply ignore the file -- leaving the file on filesystem, but just inaccessible to the current program via that filename-- for the remainder of the program?
I don't think you're guaranteed anything by the C standard, which says (N1570, 7.21.4.1 2):
The remove function causes the file whose name is the string pointed to by filename
to be no longer accessible by that name. A subsequent attempt to open that file using that
name will fail, unless it is created anew. If the file is open, the behavior of the remove
function is implementation-defined.
So, if you had a pathological implementation, it could be interpreted, I suppose, to mean that calling remove() merely has the effect of making the file invisible to this running instance of this program, but that would be, as I said, pathological.
However, all is not utterly stupid! The POSIX specification for remove() says,
If path does not name a directory, remove(path) shall be equivalent to unlink(path).
If path names a directory, remove(path) shall be equivalent to rmdir(path).
And the POSIX documentation for unlink() is pretty clear:
The unlink() function shall remove a link to a file.
Therefore, unless your implementation (a) Does not conform to POSIX requirements, and (b) is extremely pathological, you can be assured that the remove() function will actually try to delete the file, and will return 0 only if the file is actually deleted.
Of course, on most filesystems currently in use, filenames are decoupled from the actual files, so if you've got five links to an inode, that file's going to keep existing until you delete all five of them.
References:
The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
The Open Group Base Specifications Issue 7, IEEE Std 1003.1™, 2013 EditionNote:"IEEE Std 1003.1 2004 Edition" is "IEEE Std 1003.1-2001 with corrigenda incorporated". "IEEE Std 1003.1 2013 Edition" is "IEEE Std 1003.1-2008 with corrigendum incorporated".
The C99 standard does not guarantee anything.
The file could remain there for any of the reasons unlink(2) can fail. For example you don't have permission to do this.
Consult http://linux.die.net/man/2/unlink for examples what can all go wrong.
On Unix / Linux, there are several reasons for the file not to be removed:
You dont't have write permission on the file's directory (in that case, remove() will return ERROR, of course)
there is another hard link on the file. Then the file will remain on disk but only be accessible by the other path name(s)
the file is kept open by any process. In that case the directory entry is removed immediatly, so that no subsequent open() can access the file (or an appropriate call will create a new file), but the file itself will remain on disk as long as any process keeps it open.
Typically, that only unlinks the file from the file system. This means all the data that was in the file, is still there. Given enough experience or time, someone would be able to get that data back.
There are some options to not have the file be read again, ever. The *nix utility shred will do that. If you are looking to do it from within a program, open the file to write, and write nonsense data over what you are looking to 'remove'.

How to check if given argument for file reading is valid?

I am taking in an argument using fopen. What are some checks I can do to make sure that fopen actually takes in the string to a valid filename?
The number one method is to try opening the file. If fopen() returns NULL, there was an error. Check the errno variable or function to find out the problem.
Trying to preprocess a file specification is an exercise in futility. The operating system will do every relevant check for you, including those which are hard for you to do, like checking file protection ACLs, etc.
The question isn't clear, but if you want to know if the file name you have points to an existing file, you can use access (Linux documentation) (Windows documentation).

following symbolic links in C

I'm looking to write a C program which, given the name of symbolic link, will print the name of the file or directory the link points to. Any suggestions on how to start?
The readlink() function that has been mentioned is part of the answer. However, you should be aware of its horrid interface (it does not null terminate the response string!).
You might also want to look at the realpath() function, the use of which was discussed in SO 1563186. You could also look at the code for 'linkpath' at the IIUG Software Archive. It analyzes the security of all the directories encountered as a symbolic link is resolved - it uses readlink() and lstat() and stat(); one of the checks when testing the program was to ensure that realpath() resolved the name to the same file.
Make sure that you have an environment which supports POSIX functions, include unistd.h and then use the readlink function.
Depending on the platform, stat() or fstat() are probably the first things to try out. If you're on Linux or cygwin then the stat program will give you a reasonable idea of what to expect from the system API call (it pretty much gives you a text dump of it).
The system call you want is readlink(). Takes a path to the link, returns the string (not always a valid path in the filesystem!) stored in the link. Check the man page ("man 2 readlink") for details.
Note there is some ambiguity to your question. You might be asking for how to tell the "real" path in the filesystem, which is a little more complicated.

Determining the (opened) filename from a FILE *

Given a stdio FILE * pointer, is there a method by which I can discover the name of the (opened) file?
It looks (from here) that on POSIX systems you can use fileno() to get the file descriptor from a FILE*, then use fstat to get the stat info from the file descriptor. The stat structure contains the device number and inode number. You can check the filesystem for files which match the inode. This will obviously take some time for a filesystem full of stuff.
The reason that this isn't really possible (as explained in the linked article) is that a stream can have no filename if it's something like stdin or stdout, or if it's an open file that has been deleted. It can have multiple names because of hardlinks as well.
The linked article mentions this comp.lang.c FAQ which outlines the insolubility of this problem in brief.
EDIT: Thanks for the correction.
No, there isn't. Apart from anything else, the FILE * may not refer to a named file. If your application needs this facility, you wil need to maintain some kind of map
from open FILE *s to the file name you used to open them.
There is no standard defined portable solution. However, you can take a look at your OS provided API set. POSIX systems have a fstat function that takes a descriptor (not a FILE *) and returns some information.

Resources