Can opendir(pathname) change the value of the input pathname? - c

I've received some curious results while using opendir():
int dtw(char *path) {
struct stat statbuf;
...
else if (S_ISDIR(statbuf.st_mode)) {
printf("Path is: %s\n", path);
struct dirent *dirent;
DIR *dirp;
if ((dirp = opendir(path)) == NULL) {
puts("Can't open directory.");
return -1;
}
printf("Path is: %s\n", path);
}
...
}
Results in:
Path is: /home/.../etc
Path is:
The only thing that would affect path is opendir() here. Does it have side effects that I'm not seeing? Or is there something else at work?

No changes are allowed; the definition of opendir() is:
DIR *opendir(const char *dirname);
And the const says opendir() did not change it.
I wonder if your path is a pointer to freed memory? In that case, the memory may have been allocated to opendir() and you are seeing the change because you're using a dangling pointer to memory that you should not be looking at?

Related

Open() system call for directories and accessing files in sub-directories

I'm trying to open a directory and access all it's files and sub-directories and also the sub-directories files and so on(recursion).
I know i can access the files and the sub-directories by using the opendir call, but i was wondering if there is a way to do so by using the open() system call(and how?), or does the open system call only refers to files?
#include <stdio.h>
#include <dirent.h>
int main(void)
{
struct dirent *de; // Pointer for directory entry
// opendir() returns a pointer of DIR type.
DIR *dr = opendir(".");
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory" );
return 0;
}
while ((de = readdir(dr)) != NULL)
printf("%s\n", de->d_name);
closedir(dr);
return 0;
}
the following code gives me the names of the files in my directory and the names of the sub-folders, but how can I differ a file from a sub-folder so i can use recursion to access the files in the sub-folder?
any help would be appreciated
you will need to have the struct stat and the macro S_ISDIR from the , if you want to check if it is a file you can use the same method but with the macro S_ISREG.
Also when you use structures is better to allocate memory before using them.
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
int main(void)
{
struct dirent *de = malloc(sizeof(struct dirent)); // Pointer for directory entry
struct stat *info; = malloc(sizeof(struct stat));
// opendir() returns a pointer of DIR type.
DIR *dr = opendir(".");
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory" );
return 0;
}
while ((de = readdir(dr)) != NULL)
{
if((S_ISDIR(info->st_mode)
printf("Directory:%s \n", de->d_name);
else printf("File:"%s \n,de->d_name);
}
closedir(dr);
return 0;
}

Is there proper way to concatenate a base path name with a new path name?

Is there a way where you can update the char arrays of a base path with an updated path?
struct dirent *dp;
DIR *dir;
struct stat buf;
dir = opendir("./statdir/");
int x;
char base_path[11] = "./statdir/";
char* full_path;
int main(int argc, char* argv[]){
while((dp = readdir(dir)) != NULL) {
full_path = strcat(base_path, dp->d_name);
if((x = lstat(full_path, &buf)) == -1) {
perror("stat failed");
exit(1);
}
printf("Debug: %s\n", full_path);
}
closedir(dir);
return(0);
}
}
My goal is to update full_path after each loop to the base_path + whatever argument is passed to argv[] and in my directory i have two files name file1 and file2....
i.e if I ran my code and wrote ./Stat, I expected full_path to be "./statdir/file1" and then "./statdir/file2"
The results I am getting however is :
Debug: ./statdir/.
Debug: ./statdir/...
stat failed: No such file or directory
You could build the full filename using snprintf like this...
snprintf(full_path, PATH_MAX, "%s/%s",base_path, dp->d_name);
...but you'll first need to ensure that full_path has the space to contain the filename so replace
char *full_path;
with
char full_path[PATH_MAX];
You're concatenating a string onto base_path, however that array is just long enough for what you initialized with. That means you're writing past the end of the array. This invokes undefined behavior.
Also note that full_path is pointing to the start of base_path.
Instead, make full_path an array big enough to hold a full path. Then use strcpy to copy over the base path, then strcat to add on the current entry.
char full_path[100];
...
while((dp = readdir(dir)) != NULL) {
strcpy(full_path, base_path);
strcat(full_path, dp->d_name);

Why does stat fail using a name from readdir? [duplicate]

This question already has answers here:
stat() error 'No such file or directory' when file name is returned by readdir()
(2 answers)
Closed 2 years ago.
I wrote a program that print the directory name or file name. It's easy but I got something trouble.
It couldn't distinguish directory and file type. I know and I used stat.st_mode to finish it. But something is wrong:
When I use gdb to check the st_mode value, I found it was 0, except "." and "..", so here is the question: why st_mode is 0?
and that is my code:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
int main(void)
{
DIR *pDir = opendir("MyDirectory");
struct dirent *pDirent;
struct stat vStat;
if (pDir == NULL)
{
printf("Can't open the directory \"MyDirectory\"");
exit(1);
}
while ((pDirent = readdir(pDir)) != NULL)
{
stat(pDirent->d_name, &vStat);
if (S_ISDIR(vStat.st_mode))
printf("Directory: %s\n", pDirent->d_name);
else
printf("File: %s\n", pDirent->d_name);
}
closedir(pDir);
return 0;
}
Classic readdir mistake: pDirent->d_name is the name of the directory entry, not a path to the file. It's "1", "4-5.c", etc. So your stat calls are looking for a file with that name in the current directory, not under MyDirectory.
Check the return value of stat. You'll see that it's ENOENT — except for . and .., which exist in the current directory as well. When stat fails, the content of the stat structure is undefined.
If you're calling opendir in a directory other than ., then to do pretty much anything useful with the returned names, you need to build a full path. Copy the path you passed to opendir to a buffer with enough room for a slash and file name in addition, and copy each file name to that buffer. Proof-of-concept code (error checking omitted, etc.):
char *directory = "MyDirectory";
size_t directory_length = strlen(directory);
char *path = malloc(directory_length + 1 + NAME_MAX);
strcpy(path, directory);
path[directory_length] = '/';
while ((pDirent = readdir(pDir)) != NULL) {
strcpy(path + directory_length + 1, pDirent->d_name);
if (stat(path, &vStat) == -1) {
perror(path);
continue;
}
…
}

C trouble with stat

In my program stat is only working for a current directory. Can any one please help me with this.
even though I am passing parameter from main it is only working for current directory.
and source path is good it is printing correct path which I have passed from the main.
DIR *dr;
struct dirent *cur;
struct stat fi;
long int total_size = 0;
dr = opendir(source);
char *name;
printf("%s\n\n\n", source);
if (!(dr))
{
perror("opendir()");
return(1);
}
while (cur = readdir(dr))
{
if(cur->d_name[0] != '.')
{
if(stat(cur->d_name, &fi) == -1)
{
printf("error \n\n");
}
else
{
printf("%s ",cur->d_name);
printf("%ld ",fi.st_blocks);
total_size = total_size + fi.st_blocks;
}
}
}
printf("\n\ntotal_size = %ld \n", total_size);
printf("\n\n\n");
return 0;
}
cur->d_name only contains the file name.
to get a 'stat()' outside the current directory,
need to prefix with the path string.
Also need to check if the returned struct from readdir()
is a file or a sub directory.
The main problem is that stat expects a file path but d_name is just the file name. You can find a working example of how to use stat with d_name here

stat outputting the wrong values for files in a directory

I am trying to create a function that will take an inputted directory path (filrOrDir) and output info for each file in the directory: file name, size, and last access date. The program compiles and prints everything. It prints the right file names but, for each file, the size and last access date are wrong. I thought maybe it was because of my variable declarations being in the while loop but I moved them around and still go the same results. Can somebody please give me a hint or a tip on what I am doing wrong? Below is my code:
void dirInfo(char *fileOrDir)
{
DIR *d;
struct dirent *dir;
d = opendir(fileOrDir);
while((dir = readdir(d)) !=NULL)
{
struct stat *buffer = (struct stat *)malloc(sizeof(struct stat));
char accessString[256];
char *name = (char *)malloc(sizeof(char));
struct tm *tmAccess;
int size = 0;
name = dir->d_name;
stat(name, buffer);
printf("%s ", name);
size = buffer->st_size;
printf("%d bytes ", size);
tmAccess = localtime(&buffer->st_atime);
strftime(accessString, sizeof(accessString), "%a %B %d %H:%M:%S %Y", tmAccess);
printf("%s\n", accessString);
printf("\n");
free(buffer);
}
closedir(d);
}
name = dir->d_name is the name of the file inside the directory fileOrDir, but
stat(name, buffer);
tries to stat the file name in the current working directory.
That fails (unless fileOrDir happens to be the current working directory),
and therefore the contents of buffer is undetermined.
You have to concatenate the directory and the file name for the stat call.
You should also check the return value of the stat call.
For example:
char fullpath[MAXPATHLEN];
snprintf(fullpath, sizeof(fullpath), "%s/%s", fileOrDir, name);
if (stat(fullpath, buffer) == -1) {
printf(stderr, "stat failed: %s\n", strerror(errno));
} else {
// print access time etc.
}

Resources