I have a client/ server application, and i get an error there -> perror ("[server] Can't send the message to client.\n"). So the server cant' send the msgrasp ( the buffer). If you can help, I'll be grateful.
void printdir(char *dir, int depth)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if((dp = opendir(dir)) == NULL) {
fprintf(stderr,"cannot open directory: %s\n", dir);
return;
}
chdir(dir);
while((entry = readdir(dp)) != NULL) {
lstat(entry->d_name,&statbuf);
if(S_ISDIR(statbuf.st_mode)) {
/* Found a directory, but ignore . and .. */
if(strcmp(".",entry->d_name) == 0 ||
strcmp("..",entry->d_name) == 0)
continue;
printf("%*s%s/\n",depth,"",entry->d_name);
/* Recurse at a new indent level */
printdir(entry->d_name,depth+4);
}
else printf("%*s%s\n",depth,"",entry->d_name);
}
chdir("..");
closedir(dp);
}
int printForClient(int fd)
{
char buffer[100];
int bytes;
char msg[100];
char *msgrasp=NULL;
bytes = read (fd, msg, sizeof (buffer));
if (bytes < 0)
{
perror ("Can't read from client.\n");
return 0;
}
printf ("[server]..%s\n", msg);
printdir(&msgrasp,msj,0);
printf("[server]%s\n",msgrasp);
if (bytes && write (fd, msgrasp, bytes) < 0)
{
perror ("[server] Can't send the message to client.\n");
return 0;
}
return bytes;
}
This is not a very good Idea, but since it's what you requested here you have a solution with dynamic memory allocation
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
void printdir(char **output, const char *const dir, int depth)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if ((dp = opendir(dir)) == NULL)
{
fprintf(stderr,"cannot open directory: %s\n", dir);
return;
}
chdir(dir);
while ((entry = readdir(dp)) != NULL)
{
/* check if stat succeeded */
if (lstat(entry->d_name, &statbuf) == -1)
continue;
if (S_ISDIR(statbuf.st_mode) != 0)
{
char *buffer;
size_t length;
/* Found a directory, but ignore . and .. */
if(strcmp(".",entry->d_name) == 0 ||
strcmp("..",entry->d_name) == 0)
continue;
length = 4 + depth + strlen(entry->d_name);
if (*output != NULL)
length += strlen(*output);
buffer = realloc(*output, length);
if (buffer != NULL)
{
char current[length];
if (*output == NULL)
buffer[0] = '\0';
*output = buffer;
snprintf(current, length, "%*s%s/\n", depth, " ", entry->d_name);
strcat(*output, current);
//printf("%*s%s/\n",depth,"",entry->d_name);
/* Recurse at a new indent level */
}
else
{
fprintf(stderr, "Out of memory\n");
free(*output);
*output = NULL;
closedir(dp);
return;
}
printdir(output, entry->d_name, depth + 4);
}
else
{
char *buffer;
size_t length;
length = 4 + depth + strlen(entry->d_name);
if (*output != NULL)
length += strlen(*output);
buffer = realloc(*output, length);
if (buffer != NULL)
{
char current[length];
if (*output == NULL)
buffer[0] = '\0';
*output = buffer;
snprintf(current, length, "%*s%s/\n", depth, " ", entry->d_name);
strcat(*output, current);
}
else
{
fprintf(stderr, "Out of memory\n");
free(*output);
*output = NULL;
closedir(dp);
return;
}
}
}
chdir("..");
closedir(dp);
}
int main()
{
char *buffer = NULL; //buffer for printdir output.
printf("Directory scan of /home:\n");
printdir(&buffer, "/home", 0);
printf("done.\n");
printf("%s\n", buffer);
free(buffer);
exit(0);
}
It is not a very good Idea because you don't know if there will be enough memory to hold all the text, it could grow a lot, I added checks for that situation in this code, in the event of going out of memory, this function will abort reading, release resources and return.
I would suggest adding an argument of type char* (a pointer to a char array) and at every recursion advance the pointer. My try (supposing the buffer is long enough for the output):
void printdir(char *dir, int depth, char* output)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
char tmp[100];
if((dp = opendir(dir)) == NULL) {
fprintf(stderr,"cannot open directory: %s\n", dir);
return;
}
chdir(dir);
while((entry = readdir(dp)) != NULL) {
lstat(entry->d_name,&statbuf);
if(S_ISDIR(statbuf.st_mode)) {
/* Found a directory, but ignore . and .. */
if(strcmp(".",entry->d_name) == 0 ||
strcmp("..",entry->d_name) == 0)
continue;
sprintf(tmp, "%*s%s/\n",depth,"",entry->d_name);
strcpy(buffer, tmp);
/* Recurse at a new indent level */
printdir(entry->d_name,depth+4, buffer+strlen(tmp));
}
else printf("%*s%s\n",depth,"",entry->d_name);
}
chdir("..");
closedir(dp);
}
int main()
{ char buffer[1000]; //buffer for printdir output.
printf("Directory scan of /home:\n");
printdir("/home",0);
printf("done.\n");
exit(0);
}
You might want to add \n between every execution, depending on what you wish to do with the output. Please note that in this program \0 at the end of each string is deleted.
Related
I created two programs, which will communicate via named pipe, one will be reading from it and another one will be writing to it. It works pretty fine now, except for the fact, that it opens and writes to the same fifo exactly 3 times. It's my first time with C and pipes, and I don't understand why is this writing three times. Can you see why is this writing three times?
writing.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#define BUFFSIZE 512
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
void writing(char *s)
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
printf("writing to %s\n",s);
if ( (fd = open(s, O_WRONLY)) < 0)
err("open")
while( (n = read(STDIN_FILENO, buf, sizeof buf -1) ) > 0) {
buf[n-1] = '\0';
printf("Received: %s\n", buf);
if ( write(fd, buf, n) != n) {
err("write");
}
if(strcmp(buf,"END")==0){
printf("%s","exit");
break;
}
}
close(fd);
}
char* concat(const char *s1, const char *s2)
{
char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
strcpy(result, s1);
strcat(result, s2);
return result;
}
int file_stat(char *argv){
int isfifo = 0;
struct stat sb;
printf("%s",argv);
if (stat(argv, &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
printf("File type: ");
if (sb.st_mode & S_IFMT == S_IFIFO) {
printf("FIFO/pipe\n");
isfifo = 1;
}
printf("Ownership: UID=%ld GID=%ld\n",
(long) sb.st_uid, (long) sb.st_gid);
//exit(EXIT_SUCCESS);
return isfifo;
}
int main(int argc, char *argv[])
{
// READ ALL FILES IN DIRECTORY
if (argc != 2) {
fprintf(stderr, "Usage: %s /<pathname>/\n", argv[0]);
exit(EXIT_FAILURE);
}
DIR *d;
struct dirent *dir;
if ((d = opendir (argv[1])) != NULL) {
/* print all the files and directories within directory */
while ((dir = readdir (d)) != NULL) {
printf ("%s\n", dir->d_name);
char* s = concat(argv[1], dir->d_name);
if (file_stat(s) == 1) {
writing(s);
}
else {
mkfifo("fifo_x", 0666);
writing("fifo_x");
}
free(s);
}
closedir (d);
}
else {
/* could not open directory */
perror ("error: ");
return EXIT_FAILURE;
}
}
reading file is the same except for "reading" function and call to reading()
reading
void reading(char *s)
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
printf("%s",s);
if ( (fd = open(s, O_RDONLY)) < 0)
err("open");
while( (n = read(fd, buf, sizeof buf - 1) ) > 0) {
buf[n-1] = '\0';
if(strcmp(buf,"END")==0){
printf("%s\n", "exit");
break;
}
buf[n-1] = '\n';
if ( write(STDOUT_FILENO, buf, n) != n) {
exit(1);
}
}
close(fd);
}
the output
/home/..File type: Ownership: UID=0 GID=0
writing to fifo_x
END
Received: END
exitola
/home/olaFile type: Ownership: UID=1001 GID=1001
writing to fifo_x
END
Received: END
exit.
/home/.File type: Ownership: UID=0 GID=0
writing to fifo_x
END
Received: END
exit
You have three files in the directory with whose pathname you called your program. All three files are not fifo's so for each you write to fifo_x.
The file names are
.
..
olaFile
Maybe you should explicitly exclude the files
.
..
which happen to be in every directory in linux and represent the current directory . and the parent directory ...
The last Code I just posted now works. That is, it is able to copy all files from one directory to another. But now, I wanted to update it in such a way that it copies also directories including it contents be it files or folders.
Here is what I did so far, but this has been unable to accomplish my dream.
I really don't know what is wrong with the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#define Max 8192
int copy_files(char *src, char *dest);
int copy_dir(char *srcpath, char *destpath);
int copy_dir(char *srcpath, char *destpath)
{
DIR *sdp = NULL;
DIR *ddp = NULL;
struct dirent *entry;
struct stat sb;
char tempsrc[strlen(srcpath)+1];
char tempdest[strlen(destpath)+1];
strcat(srcpath, "/");
strcat(destpath, "/");
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
if( (sdp = opendir(srcpath)) == NULL )
{
printf ("%s is not an existing directory\n", srcpath);
return 0;
}
else
{
while( (entry = readdir(sdp)) )
{
stat(entry->d_name, &sb);
// printf("Cannot open directory\n");
// exit(EXIT_FAILURE);
switch (sb.st_mode & S_IFMT)
{
case S_IFREG:
{
strcat(tempdest, entry->d_name);
strcat(tempsrc, entry->d_name);
copy_files(tempsrc, tempdest);
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
break;
}
case S_IFDIR:
{
strcat(tempsrc, entry->d_name);
strcat(tempdest, entry->d_name);
mkdir(tempdest, 0777);
ddp = opendir(tempdest);
copy_dir(tempsrc, tempdest);
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
break;
}
}
}
closedir(sdp);
closedir(ddp);
return 1;
}
}
int copy_files(char *src, char *dest)
{
int sfd, dfd, ret_in, ret_out;
char buff[Max];
if ( (sfd = open(src, O_RDONLY)) == -1 )
{
printf("Error while reading %s\n", src);
perror(src);
exit(1);
}
if ( (dfd = creat(dest, 0644)) == -1 )
{
printf("Error while creating %s\n", dest);
perror(dest);
exit(1);
}
while( (ret_in = read(sfd, &buff, Max)) > 0 )
{
ret_out = write (dfd, &buff, ret_in);
if (ret_out != ret_in)
{
printf("write error to %s", dest);
perror(dest);
exit(1);
}
if (ret_in == -1)
{
printf("read error from %s", src);
perror(src);
exit(1);
}
}
close(sfd);
close(dfd);
return 1;
}
int main(int argc, char *argv[])
{
int i;
if (argc != 3)
{
printf ("Usage: Programme_name src dest\n e.g. ./cp src dest\n");
exit(1);
}
char *srcp = argv[1];
char *destp = argv[2];
if (srcp[0] == '/' && destp[0] == '/')
{
for (i = 1; i <= strlen(destp); i++)
destp[(i-1)] = destp[i];
for (i = 1; i <= strlen(srcp); i++)
srcp[(i-1)] = srcp[i];
copy_dir(srcp, destp);
}
else if (srcp[0] != '/' && destp[0] == '/') //./ass1 test /t2
{
for (i = 1; i <= strlen(destp); i++)
destp[i-1] = destp[i];
strcat(destp, "/");
strcat(destp, srcp);
copy_files(srcp, destp);
}
else
{
printf ("Usage: Programme_name src dest\n e.g. ./cp src dest\n");
exit(1);
}
}
You are indefinitely adding /. to the temporary source and destination paths when the directory entry . is read, which is present in all directories. Instead, you should skip the . and .. entries.
Another error is the dimensioning of the temporary paths:
char tempsrc[strlen(srcpath)+1];
char tempdest[strlen(destpath)+1];
The arrays are made just long enough to hold the original paths, though sub-directory names are then appended, overflowing the arrays. Better:
char tempsrc[PATH_MAX];
char tempdest[PATH_MAX];
I am working on a version of graphical ls, representing the output of ls with a tree. I have gotten most of my code working but would like to be able to determine what directory to read from in the command line. I have tried using
DIR *d
d = opendir(argv[1]);
But this does not work and results in errors opening files as well as the size and other information not updating for the file.
Any information would be greatly appreciated! Thanks.
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#define _GNU_SOURCE
#include <limits.h>
void helper(DIR *, struct dirent *, struct stat, char *, int, char **);
void dircheck(DIR *, struct dirent *, struct stat, char *, int, char **);
int main(int argc, char *argv[]){
DIR *d;
// Create dirent struct
struct dirent *dir;
// Create stat struct
struct stat buf;
// current path for file
char currentPath[FILENAME_MAX];
// Depth for tree
int depth = 0;
// Checking for correct usage
if (argc != 2) {
printf("Usage: './gls <directory_name>'\n");
exit(0);
}
// Checking that file provided in command line actually exists
if (lstat(argv[(argc - 1)], &buf) < 0) {
printf("Error: No such file exists.\n");
return 1;
exit(0);
}
// General resource for printing files: http://stackoverflow.com/questions/4204666/how-to-list-files-in-a-directory-in-a-c-program%20*/
// Open the current directory
d = opendir (".");
if(d == NULL) {
printf("Error opening directory.\n");
return 1;
}
// Store the current directory into currentPath
if((getcwd(currentPath, FILENAME_MAX)) == NULL) {
printf("Error: No such file exists.\n");
return 1;
}
// Iterate through all items in directory
while((dir = readdir(d)) != NULL){
// Do not process . and ..
if(strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
continue;
// Forms the path for lstat
getcwd(currentPath, FILENAME_MAX);
strcat(currentPath, "/");
strcat(currentPath, dir->d_name);
if(lstat(currentPath, &buf) == -1){
perror("stat");
printf("Error could not open file\n");
}
getcwd(currentPath, FILENAME_MAX);
// Checks if file is a regular file
if(S_ISREG(buf.st_mode))
printf("| %s (regular file - %d - !checksum)\n", dir->d_name, (int)buf.st_size);
// Checks if file is a directory
else if(S_ISDIR(buf.st_mode)) {
printf("| %s (directory)\n", dir->d_name);
dircheck(d, dir, buf, currentPath, depth, argv);
}
// Checks if file is a symbolic link
else if(S_ISLNK(buf.st_mode)) {
// Resource used for absolute and relative paths: http://www.apiexamples.com/c/stdlib/realpath.html
char resolved_path[PATH_MAX];
realpath(currentPath, resolved_path);
printf("| %s (symbolic link - %s)\n", dir->d_name, resolved_path);
}
// Checks if file is a FIFO
else if(S_ISFIFO(buf.st_mode)) {
printf("| %s (fifo (named pipe))\n", dir->d_name);
}
}
// Close the directory and return 0 for success
closedir(d);
return 0;
}
// Recursive helper
// Resource used for some of helper function and dircheck function: http://stackoverflow.com/questions/4989431/how-to-use-s-isreg-and-s-isdir-posix-macros
void helper(DIR *d, struct dirent *dir, struct stat buf, char currentPath[FILENAME_MAX], int depth, char *argv[]){
int i = 0;
// Open directory in currentPath
if((d = opendir(currentPath)) == NULL)
printf("Error: Failed to open Directory ==> %s\n", currentPath);
// Read through directory
while((dir = readdir(d)) != NULL){
// If file is . or .. ignore
if(strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
continue;
getcwd(currentPath, FILENAME_MAX);
strcat(currentPath, "/");
strcat(currentPath, dir->d_name);
getcwd(currentPath, FILENAME_MAX);
// If file is a register
if(S_ISREG(buf.st_mode)){
for(i = 0; i < depth; i++) {
printf(" ");
printf("%s (%d bytes)\n", dir->d_name, (int)buf.st_size);
}
}
// If file is a directory
if(S_ISDIR(buf.st_mode)) {
if(strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
dircheck(d, dir, buf, currentPath, depth, argv);
}
}
}
// Change directory back
chdir("..");
closedir(d);
}
// Resource used as guideline in order to create helper and dircheck functions
// http://stackoverflow.com/questions/4989431/how-to-use-s-isreg-and-s-isdir-posix-macros
void dircheck(DIR *d, struct dirent *dir, struct stat buf, char currentPath[FILENAME_MAX], int depth, char *argv[]){
int i = 0;
strcat(currentPath, "/");
strcat(currentPath, dir->d_name);
// If two directories exists at the same section in the tree
if((chdir(currentPath)) == -1){
getcwd(currentPath, FILENAME_MAX);
strcat(currentPath, "/");
strcat(currentPath, dir->d_name);
getcwd(currentPath, FILENAME_MAX);
// Add --- based on the depth of the tree
for(i = 0; i <= depth; i++)
printf ("---");
printf("| %s (subdirectory)\n", dir->d_name);
depth++;
helper(d, dir, buf, currentPath, depth, argv);
}
else{
// Add --- based on the depth of the tree
for(i =0; i <= depth; i++)
printf("---");
printf("| %s (subdirectory)\n", dir->d_name);
chdir(currentPath);
depth++;
helper(d, dir, buf, currentPath, depth, argv);
}
}
You are reading stat before while loop, this is dir in your case.
Then for every file in directory you are checking st_mode, but this is not updated nowhere in the while loop.
if (stat(argv[(argc - 1)], &statBuf) < 0)
this line just query the dir info, so you will always get directory type.
you should query specific file under that dir,
so you can change the code like this:
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
/* Resource: http://stackoverflow.com/questions/4204666/how-to-list-files-in-a-directory-in-a-c-program */
/* Resource: http://cboard.cprogramming.com/linux-programming/131-stat.html */
#define MAX_FILE_NAME_LEN 256
int main(int argc, char *argv[])
{
char path[MAX_FILE_NAME_LEN] = {0};
struct stat statBuf;
if (argc != 2) {
printf("Usage: './gls <directory_name>'\n");
exit(0);
}
if (stat(argv[(argc - 1)], &statBuf) < 0) {
printf("Error: No such file exists.\n");
exit(0);
}
DIR *d;
struct dirent *dir;
//char currentPath[FILENAME_MAX];
d = opendir(argv[1]);
while ((dir = readdir(d)) != NULL) {
//getcwd(currentPath, FILENAME_MAX);
//strcat(currentPath, "/");
//strcat(currentPath, dir->d_name);
//if(stat(currentPath, &statBuf) == -1){
//printf("N")
//}
memset(path, 0, MAX_FILE_NAME_LEN);
snprintf(path,MAX_FILE_NAME_LEN,"%s%s",argv[1],dir->d_name);
//getcwd(currentPath, FILENAME_MAX);
if (stat(path, &statBuf) < 0) {
printf("Error: No such file exists.\n");
continue;
// exit(0);
}
if(S_ISREG(statBuf.st_mode)) {
printf("| %s (regular file - %d - !checksum!)\n", dir->d_name, (int)statBuf.st_size); /* If regular file */
}
if(S_ISDIR(statBuf.st_mode)) {
printf("| %s (directory - size)\n", dir->d_name);
}
if(S_ISLNK(statBuf.st_mode)) {
printf("| %s (symbolic link - points to !!!\n", dir->d_name);
}
if(S_ISFIFO(statBuf.st_mode)) {
printf("| %s (fifo (named pipe))\n", dir->d_name);
}
}
closedir(d);
return(0);
}
I saw below code and change only checking file mode, I want to use stat, st_mode. But result is not same. Difference is just checking function.
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
void listdir(const char *name, int level)
{
DIR *dir;
struct dirent *entry;
if (!(dir = opendir(name)))
return;
if (!(entry = readdir(dir)))
return;
do {
if (entry->d_type == DT_DIR) {
char path[1024];
int len = snprintf(path, sizeof(path)-1, "%s/%s", name, entry->d_name);
path[len] = 0;
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
printf("%*s[%s]\n", level*2, "", entry->d_name);
listdir(path, level + 1);
}
else
printf("%*s- %s\n", level*2, "", entry->d_name);
} while (entry = readdir(dir));
closedir(dir);
}
int main(void)
{
listdir(".", 0);
return 0;
}
and just change check file_mode
void filelist(const char*loc, int dep){
DIR*dirpt;
struct dirent* dir;
if (!(dirpt = opendir(loc)))
return;
while((dir = readdir(dirpt))!=NULL)
{
struct stat buf;
lstat(dir->d_name, &buf);
if(S_ISDIR(buf.st_mode)){
char p[1024];
int l = snprintf(p, sizeof(p)-1, "%s/%s", loc, dir->d_name);
p[l] = 0;
if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
continue;
printf("%*s[%s]\n", dep*2,"", dir->d_name);
filelist(p,dep + 1);
}
else
printf("%*s- %s\n", dep*2,"", dir->d_name);
}
closedir(dirpt);
}
int main(void){
filelist(".",0);
return 0;
}
but result is not same, cannot exploring all directory....I don't know why....
lstat(dir->d_name, &buf);
In this call, dir->d_name does not capture the complete path. It is only the name of the entry in that directory. You should capture the return value of the function and make sure that it was able to get the values you need.
if ( lstat(dir->d_name, &buf) == -1 )
{
// Deal with error
}
You'll have to use something like:
while((dir = readdir(dirpt))!=NULL)
{
char p[1024];
struct stat buf;
int l = snprintf(p, sizeof(p)-1, "%s/%s", loc, dir->d_name);
p[l] = 0;
if ( lstat(dir->d_name, &buf) == -1 )
{
// Problem
continue;
}
if(S_ISDIR(buf.st_mode)){
if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
continue;
printf("%*s[%s]\n", dep*2,"", dir->d_name);
filelist(p,dep + 1);
}
else
printf("%*s- %s\n", dep*2,"", dir->d_name);
}
This is a C program I wrote to recursively navigate and output directories and regular files. It compiles and runs fine on my Linux machine. But on Solaris, the dit->d_type == 8 check and the other similar ones don't work because there is no d_type field. An answer I've read to this problem is to use the S_ISREG() and S_ISDIR() macros, but they don't work at all the way I have them in my code currently. I commented out the lines that work on my Linux machine.
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
void helper(DIR *, struct dirent *, struct stat, char *, int, char **);
void dircheck(DIR *, struct dirent *, struct stat, char *, int, char **);
int main(int argc, char *argv[]){
DIR *dip;
struct dirent *dit;
struct stat statbuf;
char currentPath[FILENAME_MAX];
int depth = 0; /*Used to correctly space output*/
/*Open Current Directory*/
if((dip = opendir(".")) == NULL)
return errno;
/*Store Current Working Directory in currentPath*/
if((getcwd(currentPath, FILENAME_MAX)) == NULL)
return errno;
/*Read all items in directory*/
while((dit = readdir(dip)) != NULL){
/*Skips . and ..*/
if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0)
continue;
if(stat(currentPath, &statbuf) == -1){
perror("stat");
return errno;
}
/*Checks if current item is of the type file (type 8) and no command line arguments
if(dit->d_type == 8 && argv[1] == NULL)*/
if(S_ISREG(statbuf.st_mode) && argv[1] == NULL)
printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
/*If a command line argument is given, checks for filename match
if(dit->d_type == 8 && argv[1] != NULL)*/
if(S_ISREG(statbuf.st_mode) && argv[1] != NULL)
if(strcmp(dit->d_name, argv[1]) == 0)
printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
/*Checks if current item is of the type directory (type 4)
if(dit->d_type == 4)*/
if(S_ISDIR(statbuf.st_mode))
dircheck(dip, dit, statbuf, currentPath, depth, argv);
}
closedir(dip);
return 0;
}
/*Recursively called helper function*/
void helper(DIR *dip, struct dirent *dit, struct stat statbuf,
char currentPath[FILENAME_MAX], int depth, char *argv[]){
int i = 0;
if((dip = opendir(currentPath)) == NULL)
printf("Error: Failed to open Directory ==> %s\n", currentPath);
while((dit = readdir(dip)) != NULL){
if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0)
continue;
stat(currentPath, &statbuf);
/*if(dit->d_type == 8 && argv[1] == NULL){*/
if(S_ISREG(statbuf.st_mode) && argv[1] == NULL){
for(i = 0; i < depth; i++)
printf(" ");
printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
}
/*if(dit->d_type == 8 && argv[1] != NULL){*/
if(S_ISREG(statbuf.st_mode) && argv[1] != NULL){
if(strcmp(dit->d_name, argv[1]) == 0){
for(i = 0; i < depth; i++)
printf(" ");
printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
}
}
/*if(dit->d_type == 4)*/
if(S_ISDIR(statbuf.st_mode))
dircheck(dip, dit, statbuf, currentPath, depth, argv);
}
}
void dircheck(DIR *dip, struct dirent *dit, struct stat statbuf,
char currentPath[FILENAME_MAX], int depth, char *argv[]){
int i = 0;
strcat(currentPath, "/");
strcat(currentPath, dit->d_name);
/*If two directories exist at the same level the path
is built wrong and needs to be corrected*/
if((chdir(currentPath)) == -1){
chdir("..");
getcwd(currentPath, FILENAME_MAX);
strcat(currentPath, "/");
strcat(currentPath, dit->d_name);
for(i = 0; i < depth; i++)
printf (" ");
printf("%s (subdirectory)\n", dit->d_name);
depth++;
helper(dip, dit, statbuf, currentPath, depth, argv);
}
else{
for(i =0; i < depth; i++)
printf(" ");
printf("%s (subdirectory)\n", dit->d_name);
chdir(currentPath);
depth++;
helper(dip, dit, statbuf, currentPath, depth, argv);
}
}
You're using S_ISREG() and S_ISDIR() correctly, you're just using them on the wrong thing.
In your while((dit = readdir(dip)) != NULL) loop in main, you're calling stat on currentPath over and over again without changing currentPath:
if(stat(currentPath, &statbuf) == -1) {
perror("stat");
return errno;
}
Shouldn't you be appending a slash and dit->d_name to currentPath to get the full path to the file that you want to stat? Methinks that similar changes to your other stat calls are also needed.
[Posted on behalf of fossuser] Thanks to "mu is too short" I was able to fix the bug. Here is my working code has been edited in for those looking for a nice example (since I couldn't find any others online).
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
void helper(DIR *, struct dirent *, struct stat, char *, int, char **);
void dircheck(DIR *, struct dirent *, struct stat, char *, int, char **);
int main(int argc, char *argv[]){
DIR *dip;
struct dirent *dit;
struct stat statbuf;
char currentPath[FILENAME_MAX];
int depth = 0; /*Used to correctly space output*/
/*Open Current Directory*/
if((dip = opendir(".")) == NULL)
return errno;
/*Store Current Working Directory in currentPath*/
if((getcwd(currentPath, FILENAME_MAX)) == NULL)
return errno;
/*Read all items in directory*/
while((dit = readdir(dip)) != NULL){
/*Skips . and ..*/
if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0)
continue;
/*Correctly forms the path for stat and then resets it for rest of algorithm*/
getcwd(currentPath, FILENAME_MAX);
strcat(currentPath, "/");
strcat(currentPath, dit->d_name);
if(stat(currentPath, &statbuf) == -1){
perror("stat");
return errno;
}
getcwd(currentPath, FILENAME_MAX);
/*Checks if current item is of the type file (type 8) and no command line arguments*/
if(S_ISREG(statbuf.st_mode) && argv[1] == NULL)
printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
/*If a command line argument is given, checks for filename match*/
if(S_ISREG(statbuf.st_mode) && argv[1] != NULL)
if(strcmp(dit->d_name, argv[1]) == 0)
printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
/*Checks if current item is of the type directory (type 4)*/
if(S_ISDIR(statbuf.st_mode))
dircheck(dip, dit, statbuf, currentPath, depth, argv);
}
closedir(dip);
return 0;
}
/*Recursively called helper function*/
void helper(DIR *dip, struct dirent *dit, struct stat statbuf,
char currentPath[FILENAME_MAX], int depth, char *argv[]){
int i = 0;
if((dip = opendir(currentPath)) == NULL)
printf("Error: Failed to open Directory ==> %s\n", currentPath);
while((dit = readdir(dip)) != NULL){
if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0)
continue;
strcat(currentPath, "/");
strcat(currentPath, dit->d_name);
stat(currentPath, &statbuf);
getcwd(currentPath, FILENAME_MAX);
if(S_ISREG(statbuf.st_mode) && argv[1] == NULL){
for(i = 0; i < depth; i++)
printf(" ");
printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
}
if(S_ISREG(statbuf.st_mode) && argv[1] != NULL){
if(strcmp(dit->d_name, argv[1]) == 0){
for(i = 0; i < depth; i++)
printf(" ");
printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
}
}
if(S_ISDIR(statbuf.st_mode))
dircheck(dip, dit, statbuf, currentPath, depth, argv);
}
/*Changing back here is necessary because of how stat is done*/
chdir("..");
closedir(dip);
}
void dircheck(DIR *dip, struct dirent *dit, struct stat statbuf,
char currentPath[FILENAME_MAX], int depth, char *argv[]){
int i = 0;
strcat(currentPath, "/");
strcat(currentPath, dit->d_name);
/*If two directories exist at the same level the path
is built wrong and needs to be corrected*/
if((chdir(currentPath)) == -1){
chdir("..");
getcwd(currentPath, FILENAME_MAX);
strcat(currentPath, "/");
strcat(currentPath, dit->d_name);
for(i = 0; i < depth; i++)
printf (" ");
printf("%s (subdirectory)\n", dit->d_name);
depth++;
helper(dip, dit, statbuf, currentPath, depth, argv);
}
else{
for(i =0; i < depth; i++)
printf(" ");
printf("%s (subdirectory)\n", dit->d_name);
chdir(currentPath);
depth++;
helper(dip, dit, statbuf, currentPath, depth, argv);
}
}