LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-11-2004, 02:30 PM   #1
Linh
Member
 
Registered: Apr 2003
Posts: 178

Rep: Reputation: 30
listing files in a directory


I got the code below from the book The C Programming Language by
Brian W. Kernighan on page 181.

I ran the program below and it did list the file named "text_file.txt"
root:/home# ./directory_1 /home/text_file.txt
1766 /home/text_file.txt


but when I ran the program using just the home directory, it goes into an infinite loop and it never list any files

root:/home# ./directory_1 /home/

fsize: can 't access /home////////////////////////////////////////////////////////////////////////////////////////////////////////¸
fsize: can 't access /home////////////////////////////////////////////////////////////////////////////////////////////////////////Ì
fsize: can 't access /home/////////////////////////////////////////////////////////////////////
==================================
Code:
#include <stdio.h>       /* standard library. a minimum requirement         */
#include <stdlib.h>      /* for oct_long = strtoul (six_oct_char, NULL, 8)  */
#include <string.h>     /* for strcmp, strcpy functions                               */
#include <fcntl.h>
#include <sys/types.h>  /* for pid_t pid;                                   */
#include <signal.h>        /* for kill(pid, SIGTERM); function        */
#include <dirent.h>        /* for DIR  *d = opendir("/proc"); declaration     */
#include <sys/stat.h>    /* for struct stat sb;                            */


typedef struct
 {
   long ino;
   char name[NAME_MAX + 1];
 } Dirent;


char *name;

void fsize(char *);


/************************************************/

void dirwalk(char *, void (*fcn)(char *));


/* fsize: print size of file "name" */

void fsize(char *name)
 {
   struct stat stbuf;
   if (stat(name, &stbuf) == -1)
    {
      fprintf(stderr, "fsize: can 't access %s\n", name);
      return;
    }

   if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
     dirwalk(name, fsize);
   printf("%8ld %s\n", stbuf.st_size, name);

 }

/************************************************/

#define MAX_PATH 1024


/* dirwalk: apply fcn to all files in dir */
void dirwalk(char *dir, void (*fcn)(char *))
 {
   char name[MAX_PATH];
   Dirent *dp;
   DIR *dfd;

   if ( (dfd = opendir(dir)) == NULL )
    {
      fprintf(stderr, "dirwalk: can 't open %s\n", dir);
      return;
    }

   while ( (dp = readdir(dfd)) != NULL )
    {
      if (strcmp(dp -> name, ".")  == 0 || strcmp(dp -> name, "..") == 0)
         continue;  /* skip self and parent directory */

      if (strlen(dir) + strlen(dp -> name) + 2 > sizeof(name))
        fprintf(stderr, "dirwalk: name %s/%s too long\n", dir, dp->name);
      else
       {
         sprintf(name, "%s/%s", dir, dp -> name);
         (*fcn)(name);
       }  /* if-then-else */
    }     /* while loop   */

    closedir(dfd);
 }

/************************************************/

/* print file sizes */
main(int argc, char **argv)
 {
    if (argc == 1)
      fsize(".");
    else
      while (--argc > 0)
        fsize(*++argv);

    return 0;
 }
 
Old 05-11-2004, 03:29 PM   #2
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
Change this:
Code:
typedef struct
{
    long ino;
    char name[NAME_MAX + 1];
} Dirent;
to:
Code:
typedef struct dirent Dirent;
And then change everywhere you see this: "dp -> name" to "dp -> d_name"

Then you get:
Code:
#include <stdio.h>       /* standard library. a minimum requirement         */
#include <stdlib.h>      /* for oct_long = strtoul (six_oct_char, NULL, 8)  */
#include <string.h>      /* for strcmp, strcpy functions                    */
#include <fcntl.h>
#include <sys/types.h>   /* for pid_t pid;                                  */
#include <signal.h>      /* for kill(pid, SIGTERM); function                */
#include <dirent.h>      /* for DIR  *d = opendir("/proc"); declaration     */
#include <sys/stat.h>    /* for struct stat sb;                             */


typedef struct dirent Dirent;


char *name;

void fsize(char *);


/************************************************/

void dirwalk(char *, void (*fcn)(char *));


/* fsize: print size of file "name" */

void fsize(char *name)
{
	 struct stat stbuf;
	 if (stat(name, &stbuf) == -1)
	 {
		  fprintf(stderr, "fsize: can 't access %s\n", name);
		  return;
	 }

	 if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
		  dirwalk(name, fsize);
	 printf("%8ld %s\n", stbuf.st_size, name);

}

/************************************************/

#define MAX_PATH 1024


/* dirwalk: apply fcn to all files in dir */
void dirwalk(char *dir, void (*fcn)(char *))
{
	 char name[MAX_PATH];
	 Dirent *dp;
	 DIR *dfd;

	 if ( (dfd = opendir(dir)) == NULL )
	 {
		  fprintf(stderr, "dirwalk: can 't open %s\n", dir);
		  return;
	 }

	 while ( (dp = readdir(dfd)) != NULL )
	 {
		  if (strcmp(dp -> d_name, ".")  == 0 || strcmp(dp -> d_name, "..") == 0)
			   continue;  /* skip self and parent directory */

		  if (strlen(dir) + strlen(dp -> d_name) + 2 > sizeof(name))
			   fprintf(stderr, "dirwalk: name %s/%s too long\n", dir, dp->d_name);
		  else
		  {
			   sprintf(name, "%s/%s", dir, dp -> d_name);
			   (*fcn)(name);
		  }  /* if-then-else */
	 }     /* while loop   */

	 closedir(dfd);
}

/************************************************/

/* print file sizes */
main(int argc, char **argv)
{
	 if (argc == 1)
		  fsize(".");
	 else
		  while (--argc > 0)
			   fsize(*++argv);

	 return 0;
}

Last edited by Hko; 05-11-2004 at 03:37 PM.
 
Old 05-11-2004, 04:01 PM   #3
Linh
Member
 
Registered: Apr 2003
Posts: 178

Original Poster
Rep: Reputation: 30
reply to Hko

Thank you hko. I got it solved.

Last edited by Linh; 05-11-2004 at 04:18 PM.
 
Old 05-11-2004, 04:19 PM   #4
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
Quote:
it works, except that when it goes into a subdirectory, it started to create that subdirectory many level deep. Forexample if it goes to /home/public/
it will create /home/public/public/public/public/public/public/public/...
and then /home/Flash/Flash/Flash/Flash/Flash/Flash/Flash/Flash/...
and so forth.
I can not reproduce that.
On my computer it works fine.
 
Old 05-11-2004, 05:19 PM   #5
Linh
Member
 
Registered: Apr 2003
Posts: 178

Original Poster
Rep: Reputation: 30
reply to Hko

Hi Hko. Thank you for your help.
Now that the code run, please help me understand a few things.

On page 180-181 of the book "The C Programming Language" Second Edition by Brian W. Kernighan, it list a bunch of declaration in order to run
a program listing files in a directory as shown in this thread. Some of that declaration are listed below.

==============================
Code:
You told me to change from: 
         typedef struct
           {
              long ino;
              char name[NAME_MAX + 1];
           } Dirent;

    to: typedef struct dirent Dirent;

1) Under what condition would I used the above structure declaration,
    instead of the one that you have suggested  which is
    typedef struct dirent Dirent ?

==============================

2) Page 180, listed these. Under what condition would I used all of these
declaration ?

typedef struct
   {
      long ino;
      char name[NAME_MAX + 1];
   } Dirent;

typedef struct
{
    int fd;
    Dirent d;
} DIR;

DIR  *opendir(char *dirname);
Dirent *readdir(DIR *dfd);
void closedir (DIR *dfd);

==============================

On page 181, the book said to use

#define S_IFMT 0160000

3) What is the number 0160000 stand for ?
4) Is the number 0160000 a Hexadecimal value ?
5) root:/home# gcc -o directory_1 directory_1.c

    directory_1.c:14: warning: `S_IFMT' redefined
    /usr/include/sys/stat.h:101: warning: this is the location 
    of the previous definition

5) When I compiled as shown above, it resulted in an error.
    Under what condition would I use 
    #define S_IFMT 0160000 ?
      
==============================

6) I also use 
    #include <syscalls.h> 
    When I compiled it gives me an error.

root:/home# gcc -o directory_1 directory_1.c
directory_1.c:7: syscalls.h: No such file or directory

6) Where would I find the library syscalls.h ?

Last edited by Linh; 05-11-2004 at 05:22 PM.
 
Old 05-11-2004, 06:09 PM   #6
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
Quote:
You told me to change from:
typedef struct
{
long ino;
char name[NAME_MAX + 1];
} Dirent;

to: typedef struct dirent Dirent;

1) Under what condition would I used the above structure declaration,
instead of the one that you have suggested which is
typedef struct dirent Dirent ?
Just don't put it directly in your .c file. The declaration differs between different versions of UNIX, and UNIX-clones like Linux. The header file "dirent.h" contains the correct declaration for the UNIX flavour it gets compiled on.

So, just #include <dirent.h> and you're fine.

When you change every "Dirent" in the program to "struct dirent" you can also delete my line ("typedef struct dirent Dirent;")

Quote:
2) Page 180, listed these. Under what condition would I used all of these
declaration ?

typedef struct
{
long ino;
char name[NAME_MAX + 1];
} Dirent;

typedef struct
{
int fd;
Dirent d;
} DIR;

DIR *opendir(char *dirname);
Dirent *readdir(DIR *dfd);
void closedir (DIR *dfd);
Same answer: Just do not put them in your .c file yourself. Just #include the header, and the right "Dirent", DIR, struct, or whatever for your Linux/UNIX flavour will be declared. This is one of the most important reasons why header files exist.

Quote:
On page 181, the book said to use

#define S_IFMT 0160000

3) What is the number 0160000 stand for ?
It's bitmask to use for 'isolating' the bits that indicate the type-of-file from the struct member "st_mode". This is needed when testing for the type of file because "st_mode" contains more infomation than only the type. Use "blabla & S_IFMT" to use the mask on "blabla".

Quote:
4) Is the number 0160000 a Hexadecimal value ?
No. It's an octal number, because it start with a '0'. A hexadecimal number would start with "0x".

Quote:
5) root:/home# gcc -o directory_1 directory_1.c
directory_1.c:14: warning: `S_IFMT' redefined
/usr/include/sys/stat.h:101: warning: this is the location
of the previous definition

5) When I compiled as shown above, it resulted in an error.
Under what condition would I use
#define S_IFMT 0160000 ?
Same answer: The right #define S_IFMT for your Linux/UNIX version is in the header. Do not #define it yourself. See the error-message:
"/usr/include/sys/stat.h:101: warning: this is the location of the previous definition"

It says it has been defined before you did. In the header "stat.h" that is...

Quote:
6) I also use
#include <syscalls.h>
When I compiled it gives me an error.

root:/home# gcc -o directory_1 directory_1.c
directory_1.c:7: syscalls.h: No such file or directory

6) Where would I find the library syscalls.h ?
#include <sys/syscall.h> probably. (Error in the book? Or is Linux different than UNIX's in this case? don't know...) Maybe you can delete that line without problems.

By the way: "syscall.h" is a header file, not a library.

Last edited by Hko; 05-11-2004 at 06:34 PM.
 
Old 05-12-2004, 09:27 AM   #7
Linh
Member
 
Registered: Apr 2003
Posts: 178

Original Poster
Rep: Reputation: 30
reply

Thank you Hko for your explanation.
 
Old 05-17-2004, 04:35 AM   #8
ahogg
LQ Newbie
 
Registered: Apr 2004
Location: Paris, France
Distribution: Mandrake 9.2
Posts: 5

Rep: Reputation: 0
Just an observation... I'm on the Kernighan and Ritchie myself, and it's an amazing reference. Most of the code examples don't compile as is though, so I'd be inclined to confirm that there are differences between UNIX and Linux in this respect. That was all!
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Apache Directory Listing Of NFS Mount, cannot view directory list via apache luqmana Linux - Networking 2 12-19-2005 06:03 AM
Listing Directory Structure RDove Programming 1 10-20-2004 11:22 AM
print listing of directory harnadem Linux - Newbie 2 04-25-2004 09:35 PM
Directory Listing mattbeekler Linux - Software 8 07-22-2003 02:27 PM
rc5.d directory listing... davee Linux - Newbie 9 06-26-2003 03:29 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:25 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration