Check if the file is directory or not - c

Program:
#include<stdio.h>
#include<stdlib.h>
#include<dirent.h>
#include<sys/stat.h>
int main(int argc, char *argv[])
{
DIR *dp;
struct dirent *dirp;
struct stat stbuf;
if (argc != 2)
printf("usage: ls directory_name\n");
if ((dp = opendir(argv[1])) == NULL)
printf("can’t open %s", argv[1]);
while ((dirp = readdir(dp)) != NULL){
stat(dirp->d_name,&stbuf);
if(S_ISDIR(stbuf.st_mode)){
printf("Directory: ");
}
printf("%s\n",dirp->d_name);
}
closedir(dp);
exit(0);
}
Output:
$ ./a.out test/
dir3
d
c
Directory: .
Directory: a
Directory: ..
Directory: dir4
Directory: dir2
Directory: dir0
Directory: b
Directory: e
Directory: dir1
$
The following are the list of files that the directory "test" contains.
$ ls -F test/
a b c d dir0/ dir1/ dir2/ dir3/ dir4/ e
$
The expected output is, if the file is directory the output will be "Directory: dir1/". Else only the file name.
But, the output of the program is not as expected. Is the program contains any error?. Is there any let me know.
Thanks in Advance...

Lets break it down into steps:
You start your program from some directory. This directory will become the process current working directory (CWD).
You call opendir on the directory test. This is actually the directory test in the CWD.
You call readdir to get the first entry in the directory.
This first entry is the . directory, which is short for current directory, all directories have it.
You call stat with ., meaning you call stat on the CWD. It of course succeeds and stat fills in the structure with all the details of the CWD.
Next iteration you get the entry a and you call stat on that entry. However since there is no a in the CWD, the stat call fails. You however doesn't check for that, and uses the stat structure that was filled in from the previous call (from the successful stat of the . directory).
And so on...
You need to tell stat to look for the entries in the given directory instead of the CWD. This can basically be done in only two ways:
Format a string so that you prefix the entry with the directory you passed to opendir. E.g.
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/%s", argv[1] ,dirp->p_name);
if (stat(path, &stbuf) != -1)
{
// `stat` call succeeded, do something
}
After calling opendir, but before looping that directory, change the CWD:
// Opendir call etc...
chdir(argv[1]);
// Loop using readdir etc.
Alternatively, start the program from the directory you want to check:
$ cd test
$ ../a.out .

Related

How to fix "recursively print subdirectories in c" [duplicate]

This question already has answers here:
stat() error 'No such file or directory' when file name is returned by readdir()
(2 answers)
Closed 3 years ago.
I have the following files/directories in my current directory. test_folder1 is a directory and there is one more directory in that directory. My C code is supposed to print all the files/directories in the current directory recursively. However, it only prints the current directory and one level down subdirectory, it does not go beyond that. Please help.
Current Directory:
a.out at.c dt dt.c main.c README test.c test_folder1.
Subdirectory of test_folder1:
ahmet.txt mehmet.txt test_folder2.
Subdirectory of test_folder2:
mahmut.txt
This for mac terminal C code.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <limits.h>
void depthFirst(DIR *dir){
struct dirent *sd;
char path[PATH_MAX];
if(dir == NULL){
printf("Error, unable to open\n");
exit(1);
}
while( (sd = readdir(dir)) != NULL){
if(strcmp(sd->d_name, ".") != 0 && strcmp(sd->d_name, "..") != 0){
printf("%s\n", sd->d_name);
realpath(sd->d_name,path);
if(isdirectory(path)){
depthFirst(opendir(sd->d_name));
}
}
}
}
int isdirectory(char *path) {
struct stat statbuf;
if (stat(path, &statbuf) == -1)
return 0;
else
return S_ISDIR(statbuf.st_mode);
}
int main(int argc, char *argv[]){
if(argc<2){
printf("No arguments");
DIR *dir;
dir = opendir(".");
depthFirst(dir);
closedir(dir);
}
This is the output
README
main.c
test.c
test_folder1
ahmet.txt
mehmet.txt
test_folder2
a.out
at.c
dt
dt.c
At the point where you're calling realpath(sd->d_name, path) for test_folder2, your current working directory is still . rather than test_folder1, so realpath() is using for ./test_folder2 rather than ./test_folder1/test_folder2.
As a result, path is the absolute path to a would-be ./test_folder2 and not ./test_folder1/test_folder2, and so your stat() call fails, meaning that test_folder2 is not a directory and therefore depthFirst() isn't called for it.
What you need to do is:
Upon entry to depthFirst(), save the current working directory (getcwd()) in some local variable and change directory (chdir()) to the directory you have as a parameter.
Before exiting depthFirst(), change directory back to the previous working directory.
You may want to have depthFirst() receive a path as a string and do the opendir() call by itself.
Let's suppose you have the following structure (program starts outside of dir_origin with dir_origin as argument):
dir_origin
README.md
dir_p0:
file1.txt
dir_p1:
file_1_1.txt
file_1_2.txt
dir_p2:
single.txt
some_other_files.txt
at this point (first recursive call):
if(isdirectory(path)){
depthFirst(opendir(sd->d_name));
You're trying to operate on dir_p0 but the process still working in the directory dir_origin/.., so you need to enter the parent of the directory you want to process first (which is dir_origin), you can do this by calling chdir on the parent directory before every recursive call to the depthFirst() and restore the working directory after the recursive call by calling chdir again with ..
Another solution to avoid changing working directory is to keep building the full path for subdirectories by joining the current path, file separator ('/') and the sub-directory to be processed before the recursive call.

On solaris how to get the full path of executable of running process programatically?

On Ubuntu we can extract full path of exe of running process by reading /proc/'pid'/exe.
On solaris there is no 'exe' file in /proc/'pid'.
I read the psinfo. But it gives just the name of process and arguments. It does not have full path of exe.
On solaris how can we do this?
My solaris version is 11.3.
Through command, you can get the full path of the exe running like this:
# ls -l /proc/<pid>/path/a.out
For e.g.
# ls -l /proc/$$/path/a.out
lrwxrwxrwx 1 root root 0 Nov 24 17:19 /proc/14921/path/a.out -> /usr/bin/bash
This way you can get the executable path.
More convinient way is:
# readlink -f /proc/<pid>/path/a.out
For e.g.:
# readlink -f /proc/$$/path/a.out
/usr/bin/bash
And programmatically you can do it like this:
#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE 1024
int main(int argc, char *argv[]) {
char outbuf[BUF_SIZE] = {'\0'};
char inbuf[BUF_SIZE] = {'\0'};
ssize_t len;
if (argc != 2) {
printf ("Invalid argument\n");
return -1;
}
snprintf (inbuf, BUF_SIZE, "/proc/%s/path/a.out", argv[1]);
if ((len = readlink(inbuf, outbuf, BUF_SIZE-1)) != -1) {
outbuf[len] = '\0';
} else {
perror ("readlink failed: ");
return -1;
}
printf ("%s\n", outbuf);
return 0;
}
It's usage:
# ./a.out <pid>
Unsure for Solaris, but some old unixes, the only thing that could be retrieved was the command name in argv[0]. Then we had to search that command in the PATH environment variable in correct order to find the full path of the command.
A bit manual but bullet proof.

stat() doesn't work on parent directory

I'm trying to code the ls command in C, but stat() refuse to open any other directory.
~/Desktop/ls$ cat bug.c
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <unistd.h>
int main(int ac, char **av)
{
DIR *d;
struct dirent *dir;
struct stat file;
d = opendir(av[1]);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
printf("%s ->", dir->d_name);
if (lstat(dir->d_name, &file) < 0)
printf(" can't read file %s!", dir->d_name);
printf("\n");
}
}
closedir(d);
return (0);
}
When running ./a.out . or any subfolder, it works correctly.
But if I write ./a.out .. , it fails to open files...
~/Desktop/ls$ ./a.out ..
.. ->
fkdkfdjkfdkfjdfkdfjkdfjkdjkfdkjf -> can't read file fkdkfdjkfdkfjdfkdfjkdfjkdjkfdkjf!
ss -> can't read file ss!
ls -> can't read file ls!
. ->
tg -> can't read file tg!
./a.out /home/login/Desktop doesn't work either, but ./a.out /home/login/Desktop/ls/ display correctly the content of the current folder.
It looks like a.out can't open parents dir, but ls -l gives :
-rwxrwxr-x 1 hellomynameis hellomynameis 13360 nov. 25 09:56 a.out
Am I doing it the wrong way ?
Thanks !
Your lstat call is wrong. When you get a name from the opened directory, it is a relative name, so you need to convert it to a correct path to let lstat locate the file:
char path[...];
sprintf(path,"%s/%s",av[1],dir->d_name);
lstat(path,...);
The program a.out may has not permission to read all the files in that folder. Try to run a.out with root permission.
And, if you want to check the error, please print the errno to get the detail of error when the lstat function does not execute success.

Manage files and folders C

I need to work with directories in a C program... The directory will be a parameter, I need to check all the files in the folder, if one of these files is a folder, I need to access it, also, I need to go back in the directories, i.e. "." and "..".
I'm using the library <dirent.h>, and right now I only can show all the content in the folder where I'm running the program (i.e. program.c, folder1, etc.). If I use something like "Desktop" as the parameter, it will show the error saying:
Couldn't open the directory: No such file or directory.
Can you tell me how to do this?
#include <dirent.h>
#include <stdio.h>
int main(int argc, char *argv[]){
DIR *dp;
struct dirent *ep;
dp = opendir (argv[1]);
if (dp != NULL){
while (ep = readdir (dp))
puts (ep->d_name);
(void) closedir (dp);
perror ("Couldn't open the directory");
}
return 0;
}
Example:
xx#xfx gcc e.c -o hola
xx#xfx ~/Desktop $ ./hola ./
hola
10475718_921955664486299_2309306989404354546_n.jpg
practica 4.tar.gz
h.c
pro
two-type-of-programmers-funny-jokes.png
as.c
a.c
prac 4
hol
Pr.hs
ej.c
du.c
.
tar
thats-racist-gif-1.gif
pract.
pract.c
e.c
prac.c
pract.c
..
Lab files #2
ejer1.c
music.pls
Lab files #4
ho2.c
dir2
ejero1.c
t
Mate
Couldn't open the directory: Success

displaying files from directory

I have a directory name called dir. It contain following files in order
12.07.2013
13.07.2013
14.07.2013
15.07.2013
16.07.2013
17.07.2013
I wrote following C program to display all the files from the directory dir
code :
#include <stdio.h>
#include <string.h>
#include <dirent.h>
int main (int argc, char *argv[])
{
DIR *directory;
struct dirent *file;
directory = opendir (argv[1]);
if (directory != NULL){
while (file = readdir (directory))
printf("FILE : %s \n",file->d_name);
(void) closedir (directory);
}
else
printf("Not able to open the directory\n");
return 0;
}
Above code give the actual output as
FILE : 14.07.2013
FILE : 13.07.2013
FILE : 17.07.2013
FILE : .
FILE : 15.07.2013
FILE : ..
FILE : 12.07.2013
FILE : 16.07.2013
but i expected output in proper order like below
FILE : 12.07.2013
FILE : 13.07.2013
FILE : 14.07.2013
FILE : 15.07.2013
FILE : 16.07.2013
FILE : 17.07.2013
When i directly see the files in directory it arranges & diplaying the files in proper order.
Then why above C code not reading file in proper order, i mean randomly reading the file.
Working environment : Linux(ubuntu12.04), gcc compiler
Thanks
It's not randomly reading the files, it's just reading the directory listing in the order it's stored in the directory file itself. When you "directly see the files in directory", I presume that means you're using ls, but ls is sorting the results before output. If you want matching output you need to do the same.

Resources