get/set logical working directory from C - c

I have a symbolic link /home/me/symlink -> /home/me/realdir
when I try to getcwd in the directory /home/me/symlink I get /home/me/realdir with the following program:
int main(int argc, char **argv)
{
int ret;
char path[PATH_MAX];
getcwd(path, PATH_MAX);
printf("path %s\n", path);
return 0;
}
Is there a way to get the directory /home/me/symlink? And, is there a way to set the current working directory to a symlinked directory?

I. No (docs)
:
The pathname shall contain no components that are dot or dot-dot, or are symbolic links.
However, there's a workaround:
char *cwd = getenv("PWD");
II. Yes (docs)
:
chdir("/path/to/newcwd");

Related

Displaying folder contents in c - Run time error

I'm trying to show what folder contains as an output. When I run this program in my harddisk after 1-2 minutes it crashes, beside of crashing part it works just fine. I dont know how I can prevent this. Can anyone help me ?
#include <string.h>
#include <stdio.h>
#include <dirent.h>
void showingFiles(DIR *, char *);
int main(void) {
DIR *folder;
char path[350];
sprintf(path, ".");
folder = opendir(path);
showingFiles(folder, path);
closedir(folder);
printf("\n\nEnter a key to close this program ");
getch();
return 0;
}
void showingFiles(DIR *currentFolder, char *path){
struct dirent *nextFile;
DIR *subFolder;
char copyPath[350];
strcpy(copyPath, path);
while ((nextFile = readdir(currentFolder)) != NULL) {
sprintf(copyPath, "%s//%s", path, nextFile->d_name);
printf("%s\n", (*nextFile).d_name);
if ((strcmp(nextFile->d_name, "..")) &&
strcmp(nextFile->d_name ,".") &&
(subFolder = opendir(copyPath)) != NULL) {
deletingFiles(subFolder, copyPath);
}
}
closedir(currentFolder);
}
There are at least 3 problems in your code that can explain the crash:
the buffers used to store the complete pathnames pay be too short and you use an unsafe sprintf to construct them, potentially causing buffer overflows.
you never close the subFolder directory handles that you open in the recursive function showingFiles, potentially running out of system handles.
you do close the directory handle currentFolder in the function showingFiles(), but is is also closed in the main() function. This causes undefined behavior. As a rule of thumb, always close the handle in the function that opened it and only there.
Less important but issues:
To name showingFiles a function that performs a recursive removal of a complete directory tree is a bit misleading.
separating directory and pathnames with double slashes // is useless and not portable. You may have been thinking of \\ and converted this Windows specific directory separator into // for Unix portability, but be aware that single forward slashes are supported by the Windows file system handlers, to you should always use / as a directory separator for programs aimed for both Unix and Windows.
Here is a modified version:
#include <dirent.h>
#include <stdio.h>
#include <string.h>
void deleteTree(DIR *, const char *);
int main(void) {
char path[350] = ".";
DIR *folder = opendir(path);
if (folder != NULL) {
deleteTree(folder, path);
closedir(folder);
}
printf("\n\nEnter a key to close this program ");
getch();
return 0;
}
void deleteTree(DIR *currentFolder, const char *path) {
char copyPath[1024];
struct dirent *nextFile;
DIR *subFolder;
while ((nextFile = readdir(currentFolder)) != NULL) {
snprintf(copyPath, sizeof(copyPath), "%s/%s", path, nextFile->d_name);
printf("%s\n", nextFile->d_name);
if (strcmp(nextFile->d_name,"..")
&& strcmp(nextFile->d_name,".")
&& (subFolder = opendir(copyPath)) != NULL) {
deletingFiles(subFolder, copyPath);
closedir(subFolder);
}
}
}

Searching through all sub directories within a directory

So I had help and now I have a program that searches through the current directory and prints out the file if it exists, now how would I make it so that it goes through a different directory and searches for the file in all the sub directories of it?
I thought if I replaced the line "." with "..", it would go back to the previous directory and go thought all the sub directories, but it only looks for the file in the directory without going in the subs.
//headers here
char *FINDME=NULL;
int filter (const struct dirent *p){
int retval=0;
if (fnmatch(FINDME,p->d_name, 0) == 0)
retval = 1;
return retval;
}
int main(int argc, char **argv){
struct dirent **namelist;
int i = 0;
FINDME = (argc > 1) ? argv[1] : "testfilename";
i = scandir("..", &namelist, filter, alphasort);
if(i < 0){
perror("scandir");
exit(1);
}
while(i--){
printf("%s\n", namelist[i]->d_name);
free(namelist[i]);
}
free(namelist);
return 0;
}
Travelling through a filesystem is actually travelling through a tree (excluding hard and symlinks), so you can use the recursive way:
The following pseudocode will give you an idea:
Function TravelDirectory (String dirname, String filename)
Foreach item=Element in dirname Do
If item.type is File AND item.name==filename
Print item
Else If item.type is Directory
TravelDirectory (item.name, filename)
EndFor
EndFunction
To implement this in C under Linux, for example, you can use the opendir()and readdir() functions instead of scandir(). readdir() will serve you as an iterator for the Foreach part.
Im not 100% certain but have you tried a wildcard or adding a trailing slash
You have ..
Try ../
OR
../*

How to check if soft link exists or not

user: ls -lt
lrwxrwxrwx 1 user sw-team 9 Jun 18 19:01 new_link -> test/file
I have a soft link like mentioned above. I want to check whether new_link(not the linked file) exists or not. I tried all the below but all are checking only if the final destination file (test/file) exists or not.
access(filename,F_OK)
stat()
open()
fopen()
I want to find it in C language not in shell script.Please tell me how to find if new_link exists before checking the linked file?
Use lstat - get symbolic link status:
The lstat() function shall be equivalent to stat(), except when path refers to a symbolic link. In that case lstat() shall return information about the link, while stat() shall return information about the file the link references.
(Emphasis mine.)
lstat will return non-zero, and errno will be set to ENOENT if the link (or any other part of the path) does not exist.
Example:
#include <stdio.h>
#include <stdbool.h>
#include <sys/stat.h>
bool symlink_exists(const char* path)
{
struct stat buf;
int result;
result = lstat(path, &buf);
return (result == 0);
}
void test(const char* path)
{
bool exists = symlink_exists(path);
printf("%s does%s exist.\n", path, exists ? "" : " not");
}
int main(int argc, char** argv)
{
test("/bin/sh");
test("/etc/no_such_thing");
return 0;
}
Output:
/bin/sh does exist.
/etc/no_such_thing does not exist.
You need lstat to get link status and readlink to read the value of symlink.
I have modified Jonthon's code. Check this:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/stat.h>
bool symlink_exists(const char* path)
{
struct stat buf;
int ret = 0;
char *linkname;
if (lstat(path, &buf) == 0) {
// TODO: Add error handling
linkname = malloc(buf.st_size + 1);
readlink(path, linkname, buf.st_size + 1);
linkname[buf.st_size] = '\0';
printf("---> '%s' points to '%s'\n", path, linkname);
if (stat(linkname, &buf) == 0)
ret = 1;
}
return ret;
}
void test(const char* path)
{
bool exists = symlink_exists(path);
printf("%s does%s exist.\n", path, exists ? "" : " *not*");
}
int main(int argc, char** argv)
{
test("/bin/sh"); //Normal link using relative path - NOT WORKING
test("/etc/no_such_thing"); //Broken file
test("tmpp"); //Normal link using absolute path - WORKING
test("tmppp"); //Broken link
return 0;
}
Use absolute path to create your links. Otherwise you have to convert it to relative paths.
Short answer:
#include <sys/stat.h>
#include <string>
bool symlinkExists(const string &path)
{
struct stat info;
return lstat(path.c_str(), &info) == 0;
}

Make dir in C, linux doesnt create sub-dirs (dir tree) - why?

I want to create a dir tree in C on linux. I wrote that code:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
static int dirExists(const char *path)
{
struct stat info;
if(stat( path, &info ) != 0)
return 0;
else if(info.st_mode & S_IFDIR)
return 1;
else
return 0;
}
int main(int argc, char **argv)
{
const char *path = "./mydir/firstdir/";
if(!dirExists(path))
{
mode_t mask = umask(0);
if(mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) == -1)
exit(-1);
umask(mask);
}
printf("%d\n", dirExists(path));
return 0;
}
Its ok when a path is a single dir, lets say, path = "./mydir" but when I want to create a dir tree, for example: path = "./mydir/a/b/c/d/" dirs are not created. Why?
You have no code to create a directory tree, so your code doesn't create a directory tree. If you want to create a directory tree, write code to do that.
What you do is create a folder who 's path is path
You need to define code that is able to create a directory tree. In other word Mkdir doesn't create directory recursively.
EDIT:
In the link you've posted the parent directory already exists.

getenv() Linux/Ubuntu returns NULL

I am trying to get a users home directory using getenv("$HOME"), but it is returning NULL. What am I doing wrong?
int main(void)
{
char * path;
path = getenv("$HOME");
printf ("The current path is: %s",path);
return 0;
}
Leave the $ off the environment variable name. When used in the shell the $ is not part of the name, but signals the shell that a variable name follows and it should substitute its value.
getenv("PATH"); // This is what you really want
And, optionally, compile with -Wall and end up with something like this. (Tested...)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *path;
path = getenv("PATH");
if(path)
printf("The current path is: %s\n", path);
return 0;
}
Shouldn't that be getenv("PATH")?
For the home directory, you could use
char* homedir = getenv("HOME");
or you could use
char* homedir = NULL;
struct passwd *pw = getpwuid(getuid());
if (pw)
homedir = pw->pw_dir;
For the PATH used by execvp use getenv("PATH")
Since HOME is an environment variable you shouldn't prefix the $ sign to it.
char *value,name[20];
scanf("%s",name);
value=getenv(name);
if(value == NULL)
printf("Not found");
else
print("value = %s",value);
Ensure that you have included unistd.h and all concerned header files.

Resources