How to get the parent directory of the current folder in a C program? - c

I am trying to get the parent directory of the current folder in which i have the program.
I need to include in the C program I have. I tried doing it through string methods and solve it, but I feel there can be a better and simpler way. Eg: If his path is “C:\Application\Config”, then I want to get - “C:\Application” the just parent path.
Can some one please help me with this?
Thanks,
Priyanka

To in-place truncate a string at its last backslash:
char pathname[MAX_PATH];
GetCurrentDirectory(MAX_PATH, pathname);
char* last_backslash = strrchr(pathname, '\\');
if (last_backslash)
{
*last_backslash = '\0';
}

Sometimes just adding \.. will suffice if you are not afraid by MAX_PATH.

It's difficult to answer your question since you haven't really specified what you want to -do- with the path once you have it. If you want to change to the new directory, that's easy, you just use whatever function you'd normally use to change directory but pass it ".." instead of a full path - that's because on all sane filesystems, ".." is a 'magic' directory which exists inside all other directories and refers to the parent thereof.
If you want to perform some string function on the new directory before jumping to it, your problem instantly becomes a lot more difficult to solve. The way I'd go about doing it mirrors RichieHindle's solution - strip the current directory away from the full path then you're left with the parent directory's path with which you can muck about to your heart's content.

In Windows OS, the API function you need is called GetCurrentDirectory().
http://msdn.microsoft.com/en-us/library/aa364934%28v=vs.85%29.aspx

Related

C program: determine which directory a file is in

What would be a good method to determine which directory a file is in? I would use realpath(), but that returns the absolute path of the file or directory to which a symlink is pointing.
For instance, if the argument is the basename of a file, and lstat() returns 0, I can confirm that the file exists. But for the purposes of the program I'm working on, I need to determine which directory that file is in.
The project is on GH, so I don't mind posting code here if it helps answer the question. Thanks!
UPDATE: Here are some specifics:
The code is near L64. If the file, dir, or symlink is in .local/share/Trash.test/files/, I need to find the corresponding trashinfo file in .local/share/Trash.test/info/.trashinfo. Normally I truncate the return value realpath() at files/, then append info/, then append the basename and .trashinfo ext. and after that, it does what I need. But when I try to get the realpath of the symlink, the absolute path to it is returned, but it's the path to what the symlink points to (e.g. /home/andy/temp/.local/share/Trash.test/files/dnsmasq -> /usr/share/doc/dnsmasq
No, realpath() does not return the absolute path of the file or directory to which a symlink is pointing. realpath() returns the absolute path of an existing file given a relative path, and as an additional benefit, if a symlink is involved in the relative path, then the symlink will be resolved.
A plain file name in the current directory is also a relative path. So, realpath() is the function you need.
Also: why not try it before posting a question?
there is no unambiguous answer to the question of "which directory hold this file". in unix-like filesystems, there can be any number of file names in any number of directories that all refer to the exact same file (hard links).
even realpath only says that it will give you one fully qualified pathname that refers to the file.
This is how I solved what I was trying to do.
This does some boundary checking. Not relevant to the problem (I see I need to add another check or two though).
buf_check (argv[restore_request], PATH_MAX);
argv[restore_request] is the file to be restored. This can be an absolute or relative path, or it can just be a basename, depending on the current working directory.
strcpy (file.relative_path, argv[restore_request]);
file.base_name = basename (argv[restore_request]);
This places a '\0' in the string: str[strlen(str) - strlen (file.base_name)], in effect, chopping off the basename.
truncate_str (file.relative_path, strlen (file.base_name));
I believe the remaining lines are self-explanatory
strcpy (file.info, file.relative_path);
strcat (file.info, "../info/");
strcat (file.info, file.base_name);
strcat (file.info, DOT_TRASHINFO);
Now the path to the info file can be found, which was the desired result.
I apologize that my question was not clear and didn't provide enough details to properly illustrate my goal. I will make it a point to write better questions in the future. Thanks to all who took the time to give me feedback.

own shell in C using execv

I am trying to build my own shell in C as part of a class project. We are required to use execv and implement our own path. For better understanding here is the question:
The list of paths is empty by default, but may grow to any arbitrary size. You should implement a built-in command to control this variable:
path [+|- /some/dir]
path (without arguments) displays all the entries in the list separated by colons, e.g. "/bin:/usr/bin".
path + /some/dir appends the given pathname to the path list.
path - /some/dir removes the given pathname from the path list.
I have misread the assignment and used execvp so far. Please can you shed some light on how to create my own path variable, and for each command executed search the directory it is in and add it to the path? Or is there any simple shell written using execv I can take a look at?
I saw http://linuxgazette.net/111/ramankutty.html, but I found the search a little too complex, and he uses execve.
so far i have char *mypath variable which is null initially. but the user can add or remove using path + some/dir or path - /some/dir. syntax for execv is execv("/some/dir", argv) how do i search my path for the executable and pass it to execv....for example mypath=/bin/ls ; when i pass execv(mypath, argv) it does not work...so how do i pass the path to execv?
I'm guessing the reason you are supposed to use excev is precisely that it doesn't take into account the path of the environment, but the call has to provide a full path to the function.
Since this is a class project, you are supposed to write your code - writing code is how you learn how to do things, much more than copy-and-paste from the internet, so I'm not going to write code to solve the problem but instead describe the solution.
You will need to keep a list of path entries - adjusted through the path + some/dir and path - some/dir mechanism - so these commands need to be handled inside your shell, of course, and they should add/remove from your list of path entries.
When you then come to executing something, say "mycommand" is entered, you will have to scan the list of path entries, and check if there is a file by the name "mycommand" in the directory specified by the path entry that can be executed (has execute bit set in the directory entry). If so, call execv on the string of current path entry and "mycommand" concatenated. (You can produce the concatenated string and use the stat function to get the information about the file, for example)
Do check for errors, and report if something goes wrong.
Please do not try to find someone else's shell on the internet. That is not how you learn, and if you don't actually learn from the class exercises, you will most likely not succeed once you finish school - and that's ultimately WHY you are going to school, right?

How do i use vfs_readdir in linux kernel?

I'm trying to use a system call to display the contents of a directory. I've been pointed in the direction of vfs_readdir, but I have no clue of how to use it or what to pass to it to get the contents of a directory. All I want to do is be able to list files in a directory similar to how ls works. (I eventually intend to store this in some sort of buffer, but for now just being able to print the contents of a dir would be enough).
I think you probably have to open the directory using filp_open.
For the "flags" argument, you proably need to put some combination of the LOOKUP_ flags listed in include/linux/namei.h
You can see what build_open_flags does here: http://lxr.linux.no/#linux+v3.1.5/fs/open.c#L876 to provide flags to filp_open.
As far as I know, filp_open IS the correct way of opening a file in kernel-space. However, doing so is discouraged.
Provided you do so from the context of a "normal" thread belonging to a user process, I think you will be ok.

Using execv() with PATH env variable

I'm writing a shell and I want to use execv() and search for the right directory through the $PATH environment variable (Yes, I know I can use execvp() and just pass the name of the file to it).
What I'm thinking about doing is getting a string from getenv("PATH"), breaking it down to separate paths then trying each one. But I was wondering if there is an easier way to do it?
I guess the question is: how does execvp() search for the right path?
Thanks!
What you described is exactly how execvp() searches the PATH. I don't think there's much point in reimplementing this yourself.

What corner cases must we consider when parsing $PATH on Linux?

I'm working on a C application that has to walk $PATH to find full pathnames for binaries, and the only allowed dependency is glibc (i.e. no calling external programs like which). In the normal case, this just entails splitting getenv("PATH") by colons and checking each directory one by one, but I want to be sure I cover all of the possible corner cases. What gotchas should I look out for? In particular, are relative paths, paths starting with ~ meant to be expanded to $HOME, or paths containing the : char allowed?
One thing that once surprised me is that the empty string in PATH means the current directory. Two adjacent colons or a colon at the end or beginning of PATH means the current directory is included. This is documented in man bash for instance.
It also is in the POSIX specification.
So
PATH=:/bin
PATH=/bin:
PATH=/bin::/usr/bin
All mean the current directory is in PATH
I'm not sure this is a problem with Linux in general, but make sure that your code works if PATH has some funky (like, UTF-8) encoding to deal with directories with fancy letters. I suspect this might depend on the filesystem encoding.
I remember working on a bug report of some russian guy who had fancy letters in his user name (and hence, his home directory name which appeared in PATH).
This is minor but I'll added it since it hasn't already been mentioned. $PATH can include both absolute and relative paths. If your crawling the paths list by chdir(2)ing into each directory, you need to keep track of the original working directory (getcwd(3)) and chdir(2) back to it at each iteration of the crawl.
The existing answers cover most of it, but it's worth covering parts of the question that wasn't answered yet:
$ and ~ are not special in the value of $PATH.
If $PATH is not set at all, execvp() will use a default value.

Resources