≡ Menu

Howto: C Programming with Directories on Linux

When it is said that in Linux everything is file then it really stands true. Most of the operations that we can do on files can be done on other entities like socket, pipe, directories etc.

There are certain situations where a software utility might have to travel across directories in the Linux system to find or match something. This is the use-case where the programmer of that utility has to deal with directory programming. So, in this article we will cover the following basics of directory programming with an example.

  1.  Creating directories.
  2.  Reading directories.
  3.  Removing directories.
  4.  Closing the directory.
  5.  Getting the current working directory.

We will go through the functions that are used for each step above and then finally we will see an example that will summarize all the directory operations.

1. Creating Directories

Linux system provides the following system call to create directories :

#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);

The ‘pathname’ argument is used for the name of the directory.

From the man page :

The argument mode specifies the permissions to use. It is modified by the process’s umask in the usual way: the permissions of the created directory are (mode & ~umask & 0777). Other mode bits of the created directory depend on the operating system. For Linux, see below.

The newly created directory will be owned by the effective user ID of the process. If the directory containing the file has the set-group-ID bit set, or if the file system is mounted with BSD group semantics (mount -o bsdgroups or, synonymously mount -o grpid), the new directory will inherit the group ownership from its parent; otherwise it will be owned by the effective group ID of the process. If the parent directory has the set-group-ID bit set then so will the newly created directory.

2. Reading Directories

A family of functions is used for reading the contents of the directory.

1. First a directory stream needs to be opened. This is done by the following system call :

#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);

From the man page :

The opendir() function opens a directory stream corresponding to the directory name, and returns a pointer to the directory stream. The stream is positioned at the first entry in the directory.

2. Next, to read the entries in directory, the above opened stream is used by the following system call :

#include
struct dirent *readdir(DIR *dirp);

From the man page :

The readdir() function returns a pointer to a dirent structure representing the next directory entry in the directory stream pointed to by dirp. It returns NULL on reaching the end of the directory stream or if an error occurred.

On Linux, the dirent structure is defined as follows:

struct dirent
{
    ino_t          d_ino;       /* inode number */
    off_t          d_off;       /* offset to the next dirent */
    unsigned short d_reclen;    /* length of this record */
    unsigned char  d_type;      /* type of file; not supported
                                   by all file system types */
    char           d_name[256]; /* filename */
};

3. Removing Directories

Linux system provides the following system call to remove directories :

#include <unistd.h>
int rmdir(const char *pathname);

From the man page :

rmdir() removes the directory represented by ‘pathname’ if it is empty. IF the directory is not empty then this function will not succeed.

4. Closing directories

Linux system provides the following system call to close the directories :

#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);

From the man page :

The closedir() function closes the directory stream associated with dirp. A successful call to closedir() also closes the underlying file descriptor associated with dirp. The directory stream descriptor dirp is not available after this call.

5. Getting Current Working Directory

Linux system provides the following system call to get the CWD :

#include <unistd.h>
char *getcwd(char *buf, size_t size);

From the man page :

The getcwd() function copies an absolute path name of the current working directory to the array pointed to by buf, which is of length size.This function returns a null-terminated string containing an absolute path name that is the current working directory of the calling process. The path name is returned as the function result and via the argument buf, if present. If the length of the absolute path name of the current working directory, including the terminating null byte, exceeds size bytes, NULL is returned, and errno is set to ERANGE; an application should check for this error, and allocate a larger buffer if necessary.

6. An Example

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

int main (int argc, char *argv[])
{
    if(2 != argc)
    {
        printf("\n Please pass in the directory name \n");
        return 1;
    }

    DIR *dp = NULL;
    struct dirent *dptr = NULL;
    // Buffer for storing the directory path
    char buff[128];
    memset(buff,0,sizeof(buff));

    //copy the path set by the user
    strcpy(buff,argv[1]);

    // Open the directory stream
    if(NULL == (dp = opendir(argv[1])) )
    {
        printf("\n Cannot open Input directory [%s]\n",argv[1]);
        exit(1);
    }
    else
    {
        // Check if user supplied '/' at the end of directory name.
        // Based on it create a buffer containing path to new directory name 'newDir'
        if(buff[strlen(buff)-1]=='/')
        {
            strncpy(buff+strlen(buff),"newDir/",7);
        }
        else
        {
            strncpy(buff+strlen(buff),"/newDir/",8);
        }

        printf("\n Creating a new directory [%s]\n",buff);
        // create a new directory
        mkdir(buff,S_IRWXU|S_IRWXG|S_IRWXO);
        printf("\n The contents of directory [%s] are as follows \n",argv[1]);
        // Read the directory contents
        while(NULL != (dptr = readdir(dp)) )
        {
            printf(" [%s] ",dptr->d_name);
        }
        // Close the directory stream
        closedir(dp);
        // Remove the new directory created by us
        rmdir(buff);
        printf("\n");
    }

    return 0;
}

The above example should be now self explanatory.

The output of above example is :

# ./direntry /home/himanshu/practice/linux

 Creating a new directory [/home/himanshu/practice/linux/newDir/]

 The contents of directory [/home/himanshu/practice/linux] are as follows
 [redhat]  [newDir]  [linuxKernel]  [..]  [ubuntu]  [.]
Add your comment

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book

Comments on this entry are closed.

  • rameshkumar June 15, 2012, 4:54 am

    Valuable article with clear example..

  • Jalal Hajigholamali June 15, 2012, 7:05 am

    Hi,
    Thanks a lot, Very useful article..

  • bob June 15, 2012, 7:20 am

    good job.

  • Tariq June 21, 2012, 3:35 pm

    why can’t you use bash script to do the same?

  • Mahesh October 17, 2012, 11:06 pm

    what are the 2 args we are supposed to give to run it??

  • Daniel June 8, 2013, 2:18 pm

    great and clear article.
    wish it showed how to run over the files in the directory as well.

  • Le Me April 6, 2016, 2:03 pm

    Quite a nasty buffer overflow you got there in the strcpy call.
    Better use strcpy_s or alternatives.