I need a method to obtain the absolute path of a file in C programming language for the implementation of 'cp' UNIX's command. The objective is show an error when the source path and destination path are the same.
There are multiple possibilities, for example:
cp file . // show error
cp ../file .
cp file file // show error
I haven't found a good method to solve this problem.
Converting comments into an answer.
Lookup realpath() to get the 'real name' of a path, but it really isn't necessary. You can use stat() to see if the device and inode number are the same for two names.
Also note that if you have two files linked (for example, /home/user1/name1 and /home/user2/name2), the names might be different but still refer to the same file (and the links could be 'hard' or symbolic). You can detect their equivalence with stat() but not with realpath() — at least, not with realpath() if the link is a hard link.
Related
This question already has answers here:
Finding current executable's path without /proc/self/exe
(14 answers)
Closed 7 years ago.
Is there a way in C/C++ to find the location (full path) of the current executed program?
(The problem with argv[0] is that it does not give the full path.)
To summarize:
On Unixes with /proc really straight and realiable way is to:
readlink("/proc/self/exe", buf, bufsize) (Linux)
readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)
readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)
On Unixes without /proc (i.e. if above fails):
If argv[0] starts with "/" (absolute path) this is the path.
Otherwise if argv[0] contains "/" (relative path) append it to cwd
(assuming it hasn't been changed yet).
Otherwise search directories in $PATH for executable argv[0].
Afterwards it may be reasonable to check whether the executable isn't actually a symlink.
If it is resolve it relative to the symlink directory.
This step is not necessary in /proc method (at least for Linux).
There the proc symlink points directly to executable.
Note that it is up to the calling process to set argv[0] correctly.
It is right most of the times however there are occasions when the calling process cannot be trusted (ex. setuid executable).
On Windows: use GetModuleFileName(NULL, buf, bufsize)
Use GetModuleFileName() function if you are using Windows.
Please note that the following comments are unix-only.
The pedantic answer to this question is that there is no general way to answer this question correctly in all cases. As you've discovered, argv[0] can be set to anything at all by the parent process, and so need have no relation whatsoever to the actual name of the program or its location in the file system.
However, the following heuristic often works:
If argv[0] is an absolute path, assume this is the full path to the executable.
If argv[0] is a relative path, ie, it contains a /, determine the current working directory with getcwd() and then append argv[0] to it.
If argv[0] is a plain word, search $PATH looking for argv[0], and append argv[0] to whatever directory you find it in.
Note that all of these can be circumvented by the process which invoked the program in question. Finally, you can use linux-specific techniques, such as mentioned by emg-2. There are probably equivalent techniques on other operating systems.
Even supposing that the steps above give you a valid path name, you still might not have the path name you actually want (since I suspect that what you actually want to do is find a configuration file somewhere). The presence of hard links means that you can have the following situation:
-- assume /app/bin/foo is the actual program
$ mkdir /some/where/else
$ ln /app/bin/foo /some/where/else/foo # create a hard link to foo
$ /some/where/else/foo
Now, the approach above (including, I suspect, /proc/$pid/exe) will give /some/where/else/foo as the real path to the program. And, in fact, it is a real path to the program, just not the one you wanted. Note that this problem doesn't occur with symbolic links which are much more common in practice than hard links.
In spite of the fact that this approach is in principle unreliable, it works well enough in practice for most purposes.
Not an answer actually, but just a note to keep in mind.
As we could see, the problem of finding the location of running executable is quite tricky and platform-specific in Linux and Unix. One should think twice before doing that.
If you need your executable location for discovering some configuration or resource files, maybe you should follow the Unix way of placing files in the system: put configs to /etc or /usr/local/etc or in current user home directory, and /usr/share is a good place to put your resource files.
In many POSIX systems you could check a simlink located under /proc/PID/exe. Few examples:
# file /proc/*/exe
/proc/1001/exe: symbolic link to /usr/bin/distccd
/proc/1023/exe: symbolic link to /usr/sbin/sendmail.sendmail
/proc/1043/exe: symbolic link to /usr/sbin/crond
Remember that on Unix systems the binary may have been removed since it was started. It's perfectly legal and safe on Unix. Last I checked Windows will not allow you to remove a running binary.
/proc/self/exe will still be readable, but it will not be a working symlink really. It will be... odd.
On Mac OS X, use _NSGetExecutablePath.
See man 3 dyld and this answer to a similar question.
For Linux you can find the /proc/self/exe way of doing things bundled up in a nice library called binreloc, you can find the library at:
http://autopackage.org/docs/binreloc/
I would
1) Use the basename() function: http://linux.die.net/man/3/basename
2) chdir() to that directory
3) Use getpwd() to get the current directory
That way you'll get the directory in a neat, full form, instead of ./ or ../bin/.
Maybe you'll want to save and restore the current directory, if that is important for your program.
I'm trying to check the given file is binary or not.
I refer the link given below to find the solution,
How can I check if file is text (ASCII) or binary in C
But the given solutions is not working properly, If I pass the .c file as argument, Its not working, It gives wrong output.
The possible files I may pass as argument:
a.out
filename.c
filename.txt
filename.pl
filename.php
So I need to know whether there is any function or way to solve the problem?
Thanks...
Note : [ Incase of any query, Please ask me before down vote ]
You need to clearly define what a binary file is for you, and then base your checking on that.
If you just want to filter based on file extensions, then create a list of the ones you consider binary files, and a list of the ones you don't consider binary files and then check based on that.
If you have a list of known formats rather then file extensions, attempt to parse the file in the formats, and if it doesn't parse / the parse result makes no sense, it's a binary file (for your purposes).
Depending on your OS, binary files begin with a header specifying that they are an executable and contain several informations about them (architecture, size, byte order etc.). So by trying to parse this header, you should know if a file is binary or not. If you are on mac, check the Mach-O file format, if you are on Linux, it should be ELF format. But beware, it's a lot of documentation.
I found a pacman project in github where a file conf.c includes a header file #include "ini.h" where ini.h contains only a single line (i.e no #include statement):
//ini.h
../common/ini.c
I have never seen anyone doing this before! It seems a bit hackish/rough around the edges. My questions are:
Is this legal C?
Is it portable?
Is it recommended?
I would have assumed the answer should be no for all these questions, but I may be learning something new...
edit
From the answers, I see its a Linux symlink. I guess that this means it is not portable to Windows, and would also make it more difficult to read outside a unix environment. I would also imagine that using relative paths (or include directories) instead of symlinks would be a better practice in cases like this for reasons mentioned above...
src/pacman/ini.h is a symbolic link according to the site.
Symbolic link has an information of where the target file is (path name), and I guess it is what is displayed on the site.
The OS will redirect access to that ini.h to ../common/ini.h, which is a normal C code.
I don't see any reason why not. The include statement indicates the compiler to replace that line with the whatever is in the included file
I want to know how to do something like the following...
I have a directory, let's call this directory "D:\Folder\" and it has some file types like .json, .lua, etc and I need to be able to put the appropriate files in a table based off their file type. How do I do this via Lua without external libraries? Also, how can I get other information on the files, like size, date modified, etc via lua and store that info?
As Yu Hao said in the comment, Lua by itself doesn't have any methods to get the list of files in a folder or access attributes of those files. In terms of external libraries, you can use Lua Filesystem module that has everything you need or winapi if you are looking for Windows-specific solution. Both are small libraries that can be compiled quite easily using mingw.
If you are looking for Windows-only-no-external-library solution, you should be able to run "dir" command and process its results using io.popen. You can parse the captured output and get file names, sizes, and dates based on that. You can also get the file size by using file:seek, but since you may be parsing anyway, you can get it all from the output. I don't think there is anything much simpler than that.
how about searching for a pattern that represents any and all characters a file could posses and then .file_type...and then run that through io.open for example...possible?
You won't be able to "guess" filenames by enumerating possible symbol combinations simply because this .... will .... take .... a .... very .... long .... time.
I was looking at getting HTML-XML-Utils working on my computer and I noticed the .e filetype in the source tree. Running:
% file types.e
types.e: ASCII c program text
reveals some clues about it and its use in C files seems to be that of a header file.
Can anyone reveal some more information or history about this filetype? I've tried my best Google-foo but I cannot find anything.
I never heard of that file type in connection with C before, but after checking the files and the Makefile it seems to be variables and functions that are exported, therefore the .e extension.
They seem to be created by a special program (which comes with the package) called cexport whose manual page states:
cexport - create header file with exported declarations from a C file