Solved

questions on chdir

Posted on 2011-03-14
31
592 Views
Last Modified: 2012-05-11
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:)
0
Comment
Question by:crazy4s
  • 17
  • 14
31 Comments
 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
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.
0
 

Author Comment

by:crazy4s
Comment Utility
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?
0
 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
> 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.
0
 

Author Comment

by:crazy4s
Comment Utility
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?
0
 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
Just remove the chdir("..") call.
I think, that is enough to make it work.
0
 

Author Comment

by:crazy4s
Comment Utility
how if i need to use chdir in my prog? i know i've to reedit the codes all, can you lead me?
0
 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
> how if i need to use chdir in my prog?
I didn't understand.
Is it mandatory to use chdir() in your code?
0
 

Author Comment

by:crazy4s
Comment Utility
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?
0
 

Author Comment

by:crazy4s
Comment Utility
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?
0
 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
> 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.
0
 
LVL 8

Expert Comment

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

Author Comment

by:crazy4s
Comment Utility
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:)
0
 

Author Comment

by:crazy4s
Comment Utility
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.
0
 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
Do this:
gdb MY core
And at the gdb prompt, give the command
bt
0
 

Author Comment

by:crazy4s
Comment Utility
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 ()
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
OK.
I will check this after I go back to office.
I don't have Linux at home.
0
 

Author Comment

by:crazy4s
Comment Utility
ok thanks first:)
0
 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
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.
0
 

Author Comment

by:crazy4s
Comment Utility
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?
0
 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
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.
0
 

Author Comment

by:crazy4s
Comment Utility
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
0
 

Author Comment

by:crazy4s
Comment Utility
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?
0
 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
So, what is your OS and gcc version?
Is there a public IP thru which I can connect to your machine and check?
0
 

Author Comment

by:crazy4s
Comment Utility
i'm using SunOS, and is our university csa machine i'm not sure whether you're able to access or not?
0
 

Author Comment

by:crazy4s
Comment Utility
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)
0
 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
> 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.
0
 

Author Comment

by:crazy4s
Comment Utility
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}.
0
 

Author Comment

by:crazy4s
Comment Utility
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)
0
 
LVL 8

Accepted Solution

by:
ssnkumar earned 500 total points
Comment Utility
OK. I installed Solaris 10 and could reproduce the problem.
Looks like this issue happens only on Solaris 10 and not even on Open Solaris!
Here is what you should do to overcome this problem.
You change this:
struct dirent entry;
to:
struct dirent *entry = (struct dirent *)malloc(sizeof(struct dirent) + PATH_MAX + 1);

And for readdir, instead of passing &entry, pass entry.
change entry.d_name to entry->d_name.

With this change, your code should not crash.

I used your first code itself. But, removed the chdir("..").
And with the change that I have suggested above, it works fine without crashing.
0
 

Author Comment

by:crazy4s
Comment Utility
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:)
0
 
LVL 8

Expert Comment

by:ssnkumar
Comment Utility
> 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.
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand and use pointers in the C programming language.
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now