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.
- Creating directories.
- Reading directories.
- Removing directories.
- Closing the directory.
- 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] [.]
Comments on this entry are closed.
Valuable article with clear example..
Hi,
Thanks a lot, Very useful article..
good job.
why can’t you use bash script to do the same?
what are the 2 args we are supposed to give to run it??
great and clear article.
wish it showed how to run over the files in the directory as well.
Quite a nasty buffer overflow you got there in the strcpy call.
Better use strcpy_s or alternatives.