Link to home
Start Free TrialLog in
Avatar of crazy4s
crazy4s

asked on

questions on chdir

Hi all,
can someone lead me on how should i use this chdir func properly in this prog...
the chdir func that i've to use here is for two reasons
1)is to switch to a new directory if the sub directory is found as a directory not file (not sure where and what i should edit my codes)
2)switch back up to the parent directory (this one i put before the end of while loop)

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>

unsigned process_directory( char *theDir )
{
    	DIR *dir = NULL;
    	struct dirent entry;
    	struct dirent *retval = 0;
    	unsigned count = 0;
	char pathName[PATH_MAX + 1];

    	/* Open the given directory, if you can. */  
    	dir = opendir( theDir );
    	if( dir == NULL ) 
	{
        	printf( "Error opening %s: %s", theDir, strerror( errno ) );
        	return 0;
    	}
	
	retval = readdir_r( dir, &entry);
    	while( retval != NULL ) 
	{
        	struct stat entryInfo;
        
        	if( ( strncmp( entry.d_name, ".", PATH_MAX ) == 0 ) || ( strncmp( entry.d_name, "..", PATH_MAX ) == 0 ) ) 
		{
            		/* Short-circuit the . and .. entries. */
            		retval = readdir_r( dir, &entry);
            		continue;
        	}
		(void)strncpy( pathName, theDir, PATH_MAX );
        	(void)strncat( pathName, "/", PATH_MAX );
        	(void)strncat( pathName, entry.d_name, PATH_MAX );
        
        	if( lstat( pathName, &entryInfo ) == 0 ) 
		{
            		/* stat() succeeded, let's party */
            		count++;
            
            		if( S_ISDIR( entryInfo.st_mode ) ) 
			{            
				/* directory */
                		printf( "processing %s/\n", pathName );
                		count += process_directory( pathName );
            		} 
			else if( S_ISREG( entryInfo.st_mode ) ) 
			{ 
				/* regular file */
                		printf( "\t%s has %lld bytes\n", pathName, (long long)entryInfo.st_size );
            		} 
			else if( S_ISLNK( entryInfo.st_mode ) ) 
			{ 
				/* symbolic link */
                		char targetName[PATH_MAX + 1];
                		if( readlink( pathName, targetName, PATH_MAX ) != -1 ) 
				{
                    			printf( "\t%s -> %s\n", pathName, targetName );
                		} 
				else 
				{
                    			printf( "\t%s -> (invalid symbolic link!)\n", pathName );
                		}
            		}
        	} 
		else 
		{
            		printf( "Error statting %s: %s\n", pathName, strerror( errno ) );
        	}
 		retval = readdir_r( dir, &entry);
		/* Switch up to parent directory
		   Now that all directories at this level have been processed*/
		chdir(".."); 
    	}
    
    	/* Close the directory and return the number of entries. */
    	(void)closedir( dir );
    	return count;
}

/* readdir_demo main()
 * 
 * Run through the specified directories, and pass them
 * to process_directory().
 */
int main( int argc, char **argv )
{
    int idx = 0;
    unsigned count = 0;
    
    for( idx = 1; idx < argc; idx++ ) {
        count += process_directory( argv[idx] );
    }
    
    return EXIT_SUCCESS;
}

Open in new window


with the chdir func i got error msg:

cpfoo@csa02 ~$ gcc as3.c -o MY
cpfoo@csa02 ~$ MY CS224
processing CS224/as3/
      CS224/as3/ourhdr.h has 4128 bytes
Error statting CS224/as3/MY: No such file or directory
Error statting CS224/as3/error.c: No such file or directory
Error statting CS224/as3/a.out: No such file or directory
Error statting CS224/as3/as3.c: No such file or directory
Error statting CS224/as1: No such file or directory
Error statting CS224/.deps: No such file or directory
Error statting CS224/test: No such file or directory
Error statting CS224/as2: No such file or directory

without the chdir:

cpfoo@csa02 ~$ gcc as3.c -o MY
cpfoo@csa02 ~$ MY CS224
processing CS224/as3/
      CS224/as3/ourhdr.h has 4128 bytes
      CS224/as3/error.c has 1837 bytes
      CS224/as3/as3.c has 2887 bytes
processing CS224/as1/
      CS224/as1/stamp-h1 has 23 bytes
      CS224/as1/configure has 137161 bytes
      CS224/as1/cpwh.c has 3503 bytes
      CS224/as1/missing has 11492 bytes
      CS224/as1/error.o has 5604 bytes
      CS224/as1/config.h.in has 625 bytes
Segmentation Fault (core dumped)

any help will be greatly appreciated:)
Avatar of Narendra Kumar S S
Narendra Kumar S S
Flag of India image

Your program is visiting all the directories recursively and lists all the files.
In this, you don't need to do chdir().
Actually you are not entering any directory here.
You are just reading the directories just like file.
If the entry inside the directory is again another directory, you will recursively call the function.
If it is a link, follow the target and if it is a regular, file print its name.
So, why do you want to do chdir().
The chdir() will change your pwd for the running program, that's all.
Avatar of crazy4s
crazy4s

ASKER

as it is stated in the assignment that i should use chdir? so i'm thinking of editing the code but i'm not sure how should i edit it?
> Error statting CS224/as3/MY: No such file or directory
The reason you are getting these errors is:
at the end of the loop, you are doing this:
>                retval = readdir_r( dir, &entry);
>                /* Switch up to parent directory
>                   Now that all directories at this level have been processed*/
>                chdir("..");
So, you have read the files of dir. And did chdir("..") - Now your pwd for the program is changed to parent directory.
Obviously, the files you got from the previous readdir() cannot be found in the parent directory.
Avatar of crazy4s

ASKER

yes i understand what you meant, i've change the working directory back to the parent directory by adding a chdir("..") here .... so what should i do now like rearrange or edit my codes, can you lead me?
Just remove the chdir("..") call.
I think, that is enough to make it work.
Avatar of crazy4s

ASKER

how if i need to use chdir in my prog? i know i've to reedit the codes all, can you lead me?
> how if i need to use chdir in my prog?
I didn't understand.
Is it mandatory to use chdir() in your code?
Avatar of crazy4s

ASKER

btw without the chdir func why will i get a segmentation fault at the end?
but when i change to use another directory it seems to be no prob?
Avatar of crazy4s

ASKER

well is not a necessary but the lecturer used this func when explaining to us so i thought of using this as the recursive func, is that possible to make a changes in my current prog to fit this chdir func in?
> btw without the chdir func why will i get a segmentation fault at the end?
Do you have gdb installed? If so, can you use the core file in gdb and get the stack trace?
That will tell you where your code is dumping core.

I can help you to debug your code. But, I can do it after another 5-6 hours are so.
> is that possible to make a changes in my current prog to fit this chdir func in?
I will check and let you know.
Avatar of crazy4s

ASKER

yes i have gdb...but because the user have to input the directory at the command line so i'm not sure how to gdb this --> usually i do it like that
gcc as3.c -g MY
gdb MY

> is that possible to make a changes in my current prog to fit this chdir func in?
I will check and let you know.

thank you:)
Avatar of crazy4s

ASKER

hmm not too sure how to check this thing... i'm always having prob with using gdb:(

cpfoo@csa02 ~$ gcc as3.c -g
cpfoo@csa02 ~$ MY CS224
processing CS224/as3/
        CS224/as3/ourhdr.h has 4128 bytes
        CS224/as3/error.c has 1837 bytes
        CS224/as3/as3.c has 2887 bytes
processing CS224/as1/
        CS224/as1/stamp-h1 has 23 bytes
        CS224/as1/configure has 137161 bytes
        CS224/as1/cpwh.c has 3503 bytes
        CS224/as1/missing has 11492 bytes
        CS224/as1/error.o has 5604 bytes
        CS224/as1/config.h.in has 625 bytes
Segmentation Fault (core dumped)

cpfoo@csa02 ~$ gdb MY
GNU gdb 6.6
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "sparc-sun-solaris2.8"...
(no debugging symbols found)
(gdb) b process_directory
Breakpoint 1 at 0x10864
(gdb) r
Starting program: /home/ugrad/cpfoo/MY
(no debugging symbols found)
warning: Temporarily disabling breakpoints for unloaded shared library "/usr/lib/ld.so.1"
(no debugging symbols found)
(no debugging symbols found)

Program exited normally.
(gdb) n
The program is not being run.
Do this:
gdb MY core
And at the gdb prompt, give the command
bt
Avatar of crazy4s

ASKER

Core was generated by `MY CS224'.
Program terminated with signal 11, Segmentation fault.
#0  0xff2e5694 in readdir64_r () from /usr/lib/libc.so.1
(gdb) bt
#0  0xff2e5694 in readdir64_r () from /usr/lib/libc.so.1
#1  0xff2e57f4 in readdir_r () from /usr/lib/libc.so.1
#2  0x00010b90 in process_directory ()
#3  0x00010a4c in process_directory ()
#4  0x00010c0c in main ()
OK.
I will check this after I go back to office.
I don't have Linux at home.
Avatar of crazy4s

ASKER

ok thanks first:)
I removed chdir("..") on line# 80 of your code.
I am using CentOS Linux and gcc 4.1.2.
Your code compiled without any errors or warnings.
And executed without any problem.
It listed out all the files in my directory with the corresponding sizes.
Also it recursively went into each subdirectory and processed all the directories and files in that.

So, if you remove chdir(".."), your code should work fine.

If you are still experiencing the crash, I would like to know the OS you are using and the gcc version.
Avatar of crazy4s

ASKER

i'm using SunOS.... but this prob only occurred for this directory i'm not sure why but it works fine for other directory:(
btw how if i want to use the chdir func in my prog, is that a possible to make a slight change and it can still works the same?
And you can use chdir() in your code, by modifying your code as suggested below:
Change the following line (line# 21) in the code that you have posted in your first post:
dir = opendir( theDir );
to:
chdir(theDir);
dir = opendir(".");

And add the line (after the while loop ends):
chdir("..");

I am assuming that, you have already removed the chdir("..") that you had originally at line# 80.

Let me know, if you get into any issues with this.
Avatar of crazy4s

ASKER

i added the few lines but it seems to has the same prob:(

cpfoo@csa02 ~$ gcc as3.c -o MY
cpfoo@csa02 ~$ MY CS224
Error statting CS224/as3: No such file or directory
Error statting CS224/as1: No such file or directory
Error statting CS224/.deps: No such file or directory
Error statting CS224/test: No such file or directory
Error statting CS224/as2: No such file or directory
Avatar of crazy4s

ASKER

is that a possibility some of the files that will make the prog to have segmentation fault? as i got the same prob for those directory that have quite many of files in it, but no problem when the directory is just 5 files?
So, what is your OS and gcc version?
Is there a public IP thru which I can connect to your machine and check?
Avatar of crazy4s

ASKER

i'm using SunOS, and is our university csa machine i'm not sure whether you're able to access or not?
Avatar of crazy4s

ASKER

i tried to search on the net on how to bt and print out those lines here is what i get for the segmentation fault?

(gdb) bt
#0  0xff2e5694 in readdir64_r () from /usr/lib/libc.so.1
#1  0xff2e57f4 in readdir_r () from /usr/lib/libc.so.1
#2  0x00010b90 in process_directory (theDir=0xffbff4c8 "CS224/as1") at as3.c:83
#3  0x00010a4c in process_directory (theDir=0xffbffaeb "CS224") at as3.c:57
#4  0x00010c0c in main (argc=2, argv=0xffbff9dc) at as3.c:105
(gdb) up
#1  0xff2e57f4 in readdir_r () from /usr/lib/libc.so.1
(gdb) n
The program is not being run.
(gdb) up
#2  0x00010b90 in process_directory (theDir=0xffbff4c8 "CS224/as1") at as3.c:83
83                      retval = readdir_r( dir, &entry);
(gdb) up
#3  0x00010a4c in process_directory (theDir=0xffbffaeb "CS224") at as3.c:57
57                                      count += process_directory( pathName );
(gdb) up
#4  0x00010c0c in main (argc=2, argv=0xffbff9dc) at as3.c:105
105             count += process_directory( argv[idx] );

which where the process stops at as1(argv= 2)


cpfoo@csa02 ~$ gcc as3.c -o MY -g
cpfoo@csa02 ~$ MY CS224
processing CS224/as3/
        CS224/as3/ourhdr.h has 4128 bytes
        CS224/as3/error.c has 1837 bytes
        CS224/as3/as3.c has 2887 bytes
processing CS224/as1/
        CS224/as1/stamp-h1 has 23 bytes
        CS224/as1/configure has 137161 bytes
        CS224/as1/cpwh.c has 3503 bytes
        CS224/as1/missing has 11492 bytes
        CS224/as1/error.o has 5604 bytes
        CS224/as1/config.h.in has 625 bytes
Segmentation Fault (core dumped)
> i'm using SunOS,
Is it Solaris 10 or Open Solaris?

In your readdir_r() manpage, I see this:
       The caller must allocate storage pointed to by entry to be large enough
       for  a  dirent structure with an array of char d_name member containing
       at least NAME_MAX (that is, pathconf(directory, _PC_NAME_MAX)) plus one
       elements. (_PC_NAME_MAX is defined in  <unistd.h>.)

So, have you taken care of this allocation of storage for entry?
In your program, you have:
struct dirent entry;
So, you need not allocate anything for entry.
But, what about the member d_name?
Check dirent.h and see if it is a pointer. If so, use malloc() to allocate memory of at least NAME_MAX and check if that works.
Avatar of crazy4s

ASKER

i'm using this Sun Microsystems Inc.   SunOS 5.10      Generic January 2005
it doesn't looks like a pointer but just a char?
hmm what should i do next now?
DESCRIPTION
     The internal  format  of  directories  is  unspecified.  The
     <dirent.h> header defines the following type:

     DIR             A type representing a directory stream.

     The header also defines the structure dirent, which includes
     the following members:

     ino_t d_ino        /* file serial number */
     char  d_name[]     /* name of entry */

     The type ino_t is defined as described in <sys/types.h>. See
     types(3HEAD).

     The character array d_name is of unspecified size,  but  the
     number of bytes preceding the terminating null byte must not
     exceed {NAME_MAX}.
Avatar of crazy4s

ASKER

i've decided not use chdir since it gets error in stat...
so this is my latest code and output
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>

unsigned DirTrav( char *theDir )
{
    	DIR *dir = NULL;
    	struct dirent entry;		// storage for entry
    	int retval = 0;			// initialize return value as 0
	struct dirent *entryPtr = NULL;	// entryPtr is set to NULL (end of directory)
    	unsigned count = 0;		// number of entries for directory
	char pathName[PATH_MAX + 1];	// additional 1 char for NULL

    	/* Open the given directory, if you can. */  
	dir = opendir( theDir );	

    	if( dir == NULL ) 
	{
        	printf( "Error opening %s: %s\n", theDir, strerror( errno ) );	//Error for opening the given directory
        	return 0;
    	}

	/*get information about the first entry*/
	retval = readdir_r( dir, &entry, &entryPtr);
    	while( entryPtr != NULL ) 
	{
        	struct stat entryInfo;
        	
		// Skip over self & parent directory records
        	if( ( strncmp( entry.d_name, ".", PATH_MAX ) == 0 ) || ( strncmp( entry.d_name, "..", PATH_MAX ) == 0 ) ) 
		{
            		/* Short-circuit the . and .. entries. */
			retval = readdir_r( dir, &entry, &entryPtr); // returns the next entry
            		continue;
        	}

		(void)strncpy( pathName, theDir, PATH_MAX );	// copy the directory to the pathName given the length of string
        	(void)strncat( pathName, "/", PATH_MAX );	// concatenate a slash right after the pathName
        	(void)strncat( pathName, entry.d_name, PATH_MAX );	// concatenate  the new directory found after the slash
        
		// check whether it is a directory or file
        	if( lstat( pathName, &entryInfo ) == 0 ) 
		{
            		count++;
            		
			/* directory */
            		if( S_ISDIR( entryInfo.st_mode ) ) 
			{            
                		printf( "processing %s/\n", pathName );
				// if it's a directory recursively call DirTrav() on the directory
				// and add the number of entries it found to the running total.
                		count += DirTrav( pathName );

            		} 
			/* regular file */
			else if( S_ISREG( entryInfo.st_mode ) ) 
			{ 
				// If it's a file, print the name and the number of bytes 
                		printf( "\t%s has %lld bytes\n", pathName, (long long)entryInfo.st_size );
            		} 

        	} 
		else 
		{
            		printf( "Error statting %s: %s\n", pathName, strerror( errno ) );	// Error
        	}

		retval = readdir_r( dir, &entry, &entryPtr);
 
    	}

    	/* Close the directory and return the number of entries. */
    	(void)closedir( dir );
    	return count;
}

/* readdir_demo main()
 * 
 * Run through the specified directories, and pass them
 * to DirTrav().
 */
int main( int argc, char **argv )
{
    	int idx = 0;
    	unsigned count = 0;	// number of entries

        /* check args   */
        if ( argc != 2 )
        	printf("usage: ./a.out <directory>\n");	//usage message if the user doesn't provide enough arguments
    
    	for( idx = 1; idx < argc; idx++ ) 
	{
		// call DirTrav() on the directory
		// and add the number of entries it found to the running total.
        	count += DirTrav( argv[idx] );
    	}
    
    	return EXIT_SUCCESS;	// return 0 if success else -1 for error
}

Open in new window


output:

cpfoo@csa02 ~$ gcc as3.c -D_POSIX_PTHREAD_SEMANTICS
cpfoo@csa02 ~$ ./a.out CS224
processing CS224/as3/
        CS224/as3/ourhdr.h has 4128 bytes
        CS224/as3/error.c has 1837 bytes
        CS224/as3/as3.c has 2887 bytes
processing CS224/as1/
        CS224/as1/cpwh.c has 3503 bytes
        CS224/as1/error.o has 5604 bytes
        CS224/as1/configure.ac has 186 bytes
Segmentation Fault (core dumped)
ASKER CERTIFIED SOLUTION
Avatar of Narendra Kumar S S
Narendra Kumar S S
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of crazy4s

ASKER

i don't really understand why we need to do the memory allocation at the struct for entry, can you explain?

>>change entry.d_name to entry->d_name.
I have the same problem in my last assignment too but somehow I'm still not sure when to use -> when to use.???

btw thanks:)
> i don't really understand why we need to do the memory allocation at the struct for entry, can you
> explain?
In the dirent structure d_name member is an array with just 1 byte.
This is not enough to hold the complete filename.
That's why in the manpage of readdir_r, it is clearly mentioned that:
       The caller must allocate storage pointed to by entry to be large enough
       for  a  dirent structure with an array of char d_name member containing
       at least NAME_MAX (that is, pathconf(directory, _PC_NAME_MAX)) plus one
       elements. (_PC_NAME_MAX is defined in  <unistd.h>.)

In manpage of another OS, it says this:
        Since the size of the structure may vary depending on the length of d_name, one should provide,
        through buf, a struct dirent with at least {NAME_MAX} bytes for d_name.

>> change entry.d_name to entry->d_name.
> I have the same problem in my last assignment too but somehow I'm still not sure when to use ->
> when to use.???
When you declare struct dirent entry, use entry.d_name.
When you declare struct dirent *entry, use entry->d_name.
So the rule is, use "->" operator  when you are dereferencing a pointer.
Otherwise use "." operator.

Let me know if it is still not clear.