In this article we will extend our code to print more comprehensive information about a file/directory in a directory. Please Refer Developing Linux Utility like 'ls' in C Developing Linux Utility - Part II Arranging Output in Alphabetical Order Example Code: $ ls -l total 148 -rwxr-xr-x 1 himanshu family 13630 2011-12-27 06:16 alpha -rw-r--r-- 1 himanshu family 3828 2011-09-11 16:04 article_function_pointer.txt -rw-r--r-- 1 himanshu himanshu 155 2011-04-24 10:58 chmodOctal.txt drwxr-xr-x 9 himanshu himanshu 4096 2011-12-24 09:02 Desktop drwxr-xr-x 2 himanshu himanshu 4096 2011-12-01 08:15 Documents drwxr-xr-x 9 himanshu himanshu 4096 2011-12-27 05:55 Downloads drwxr-xr-x 2 root root 4096 2011-12-03 22:07 google drwxr-xr-x 2 himanshu himanshu 4096 2011-03-12 06:31 Music -rwxr-xr-x 1 himanshu family 13352 2011-12-24 15:09 my_ls -rw-r--r-- 1 himanshu family 8452 2011-12-27 06:24 my_ls_alpha.c -rw-r--r-- 1 himanshu family 4433 2011-12-24 14:57 my_ls.c -rw-r--r-- 1 himanshu himanshu 16904 2011-04-16 17:58 output.log drwxr-xr-x 3 himanshu himanshu 4096 2011-04-02 13:12 Pictures drwxr-xr-x 7 himanshu family 12288 2011-12-26 22:39 practice drwxr-xr-x 2 himanshu himanshu 4096 2011-03-12 06:31 Public drwxr-xr-x 2 himanshu himanshu 4096 2011-03-12 06:31 Templates -rw-r--r-- 1 root root 1014 2011-08-16 23:27 testdisk.log -rw-r--r-- 1 himanshu himanshu 0 2011-04-24 12:16 testfile -rw-r--r-- 1 himanshu himanshu 436 2011-04-17 08:54 test.py -rw-r--r-- 1 himanshu family 3739 2011-09-11 18:42 Unsaved Document 1 drwxr-xr-x 2 himanshu himanshu 4096 2011-03-12 06:31 Videos drwxr-xr-x 2 root root 4096 2011-12-03 22:43 vlc drwxr-xr-x 6 himanshu family 4096 2011-07-03 17:07 worm As you can see in the above output, we have used the standard Linux command 'ls -l' and it displays a very detailed information about each file. The first column gives the permission for owner, group and others. Then number of hard links to the file are displayed. Then we have the user and the group name. Then the size of the file is displayed. Then we have the date and time of file creation. Finally we have file name. Lets write a code that generated information close to the example shown above. The code Here is the code : Code: #include<stdio.h> #include<string.h> #include<stdlib.h> #include <sys/types.h> #include <dirent.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <pwd.h> #include <grp.h> #include <time.h> #define RESET_COLOR "\e[m" #define MAKE_GREEN "\e[32m" #define MAKE_BLUE "\e[36m" int main(void) { char *curr_dir = NULL; DIR *dp = NULL; struct dirent *dptr = NULL; unsigned int count = 0; long *ptr = NULL; struct winsize w; //to get the number of rows and column visible on terminal ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); // Fetch the environment variable PWD so as to get the // Current working directory curr_dir = getenv("PWD"); if(NULL == curr_dir) { printf("\n ERROR : Could not get the working directory\n"); return -1; } // Variable to hold number of files inside the directory int num_files = 0; // opne the directory dp = opendir((const char*)curr_dir); // Start reading the directory contents while(NULL != (dptr = readdir(dp))) { // Do not count the files beginning with '.' if(dptr->d_name[0] != '.') num_files++; } // Our aim was to count the number of files/folders // inside the current working directory. Since its // done so close the directory. closedir(dp); // Restore the values back as we will be using them // later again dp = NULL; dptr = NULL; // Check that we should have at least one file/folder // inside the current working directory if(!num_files) { return 0; } else { // Allocate memory to hold the addresses of the // names of contents in current working directory ptr = malloc(num_files*8); if(NULL == ptr) { printf("\n Memory allocation failed\n"); return -1; } else { // Initialize the memory by zeros memset(ptr,0,num_files*8); } } // Open the directory again dp = opendir((const char*)curr_dir); if(NULL == dp) { printf("\n ERROR : Could not open the working directory\n"); free(ptr); return -1; } // Start iterating the directory and read all its contents // inside an array allocated above. unsigned int j = 0; for(count = 0; NULL != (dptr = readdir(dp)); count++) { if(dptr->d_name[0] != '.') { ptr[j] = (long)dptr->d_name; j++; } } // Start sorting the names alphabetically // Using bubble sorting here for(count = 0; count< num_files-1;count++) { for(j=count+1; j< (num_files);j++) { char *c = (char*)ptr[count]; char *d = (char*)ptr[j]; // Check that the two characters should be from same set if( ((*c >= 'a') && (*d >= 'a')) || ((*c <='Z') && (*d <='Z')) ) { int i = 0; // If initial characters are same, continue comparing // the characters until a difference is found if(*c == *d) { while(*(c+i)==*(d+i)) { i++; } } // Check if the earlier stored value is alphabetically // higher than the next value if(*(c+i) > *(d+i)) { // If yes, then swap the values long temp = 0; temp = ptr[count]; ptr[count] = ptr[j]; ptr[j] = temp; } } else { // if the two beginning characters are not from // the same ascii set then make them same and then // compare. int off_1=0, off_2=0; if(*c <= 'Z') { off_1 = 32; } if(*d <= 'Z') { off_2 = 32; } int i = 0; // After the character set are made same, check if the // beginning characters are same. If yes, then continue // searching until we find some difference. if(*c+ off_1 == *d + off_2) { while(*(c+off_1+i)==*(d+off_2+i)) { i++; } } // After difference is found, check if a swap is required. if((*c + off_1+i) > (*d + off_2+i)) { // If yes, go ahead and do the swap long temp = 0; temp = ptr[count]; ptr[count] = ptr[j]; ptr[j] = temp; } } } } // Now the names are sorted alphabetically // Start displaying on console. for(count = 0; count< num_files; count++) { int fd = -1; struct stat st; fd = open((char*)ptr[count], O_RDONLY, 0); if(-1 == fd) { printf("\n Opening file/Directory failed\n"); free(ptr); return -1; } // Call fstat to get the stat info about the file if(fstat(fd, &st)) { // If fstat() fails printf("\n Fstat() failed\n"); close(fd); free(ptr); return -1; } // Check if a directory if(S_ISDIR(st.st_mode)) { printf("d"); } else { printf("-"); } // Check the owner permission mode_t permission = st.st_mode & S_IRWXU; if(permission & S_IRUSR) { printf("r"); } else { printf("-"); } if(permission & S_IWUSR) { printf("w"); } else { printf("-"); } if(permission & S_IXUSR) { printf("x"); } else { printf("-"); } // CHeck the group permission permission = st.st_mode & S_IRWXG; if(permission & S_IRGRP) { printf("r"); } else { printf("-"); } if(permission & S_IWGRP) { printf("w"); } else { printf("-"); } if(permission & S_IXGRP) { printf("x"); } else { printf("-"); } // CHeck other's permission permission = st.st_mode & S_IRWXO; if(permission & S_IROTH) { printf("r"); } else { printf("-"); } if(permission & S_IWOTH) { printf("w"); } else { printf("-"); } if(permission & S_IXOTH) { printf("x"); } else { printf("-"); } // Print the number of hard links printf(" %d ", (int)st.st_nlink); // Get the user name struct passwd *pt = getpwuid(st.st_uid); printf("%s ",pt->pw_name); // Get the group name struct group *p = getgrgid(st.st_gid); printf("%s ",p->gr_name); // Get the file size printf("%lld ",(long long) st.st_size); // Get the date and time // Note that some logic is applied here // so as to remove the trailing newline. char date_time[100]; memset(date_time,0,sizeof(date_time)); strncpy(date_time, ctime(&st.st_ctime), sizeof(date_time)); int c = 0; while(date_time[c] != '\0') { if(date_time[c] == '\n') date_time[c] = '\0'; c++; } printf("%s ", date_time); // Check if the file/folder is executable. if(!access((const char*)ptr[count],X_OK)) { if(S_ISDIR(st.st_mode)) { // If folder, print in blue printf(MAKE_BLUE"%s\n"RESET_COLOR,(char*)ptr[count]); } else { // If executable file, print in green printf(MAKE_GREEN"%s\n"RESET_COLOR,(char*)ptr[count]); } } else { // If normal file, print by the default way(black color) printf("%s\n",(char*)ptr[count]); } close(fd); } //Free the allocated memory free(ptr); return 0; } In the code above : We have used the object of structure stat filled by the function fstat() We have used various bit mask operations to get the permissions for owner, group and others. We have used the ctime() API to convert the time into a displayable format. Now lets see the output : Code: $ ./my_ls -rwxr-xr-x 1 himanshu family 13630 Tue Dec 27 06:16:31 2011 alpha -rw-r--r-- 1 himanshu family 3828 Sun Sep 11 16:04:53 2011 article_function_pointer.txt -rw-r--r-- 1 himanshu himanshu 155 Sun Apr 24 10:58:15 2011 chmodOctal.txt drwxr-xr-x 9 himanshu himanshu 4096 Sat Dec 24 09:02:37 2011 Desktop drwxr-xr-x 2 himanshu himanshu 4096 Thu Dec 1 08:15:50 2011 Documents drwxr-xr-x 9 himanshu himanshu 4096 Tue Dec 27 05:55:36 2011 Downloads drwxr-xr-x 2 root root 4096 Sat Dec 3 22:07:11 2011 google -rwxr-xr-x 1 himanshu family 13352 Sat Dec 24 15:09:36 2011 my_ls drwxr-xr-x 2 himanshu himanshu 4096 Sat Mar 12 06:31:00 2011 Music -rw-r--r-- 1 himanshu family 4433 Sat Dec 24 14:57:25 2011 my_ls.c -rw-r--r-- 1 himanshu family 8452 Tue Dec 27 06:24:18 2011 my_ls_alpha.c -rw-r--r-- 1 himanshu himanshu 16904 Sat Apr 16 17:58:18 2011 output.log drwxr-xr-x 3 himanshu himanshu 4096 Sat Apr 2 13:12:39 2011 Pictures drwxr-xr-x 2 himanshu himanshu 4096 Sat Mar 12 06:31:00 2011 Public drwxr-xr-x 7 himanshu family 12288 Mon Dec 26 22:39:38 2011 practice -rw-r--r-- 1 himanshu himanshu 436 Sun Apr 17 08:54:27 2011 test.py -rw-r--r-- 1 root root 1014 Tue Aug 16 23:27:19 2011 testdisk.log drwxr-xr-x 2 himanshu himanshu 4096 Sat Mar 12 06:31:00 2011 Templates -rw-r--r-- 1 himanshu himanshu 0 Sun Apr 24 12:16:35 2011 testfile -rw-r--r-- 1 himanshu family 3739 Sun Sep 11 18:42:55 2011 Unsaved Document 1 drwxr-xr-x 2 himanshu himanshu 4096 Sat Mar 12 06:31:00 2011 Videos drwxr-xr-x 2 root root 4096 Sat Dec 3 22:43:08 2011 vlc drwxr-xr-x 6 himanshu family 4096 Sun Jul 3 17:07:07 2011 worm We see that the above output is quite close to the output of standard 'ls -l' utility described in the beginning of this article. Only some indentation in display is required. Conclusion To conclude, In this article we extended our code so that it can print the detailed information about file just like we get with the command 'ls -l' Stay tuned for more!!!
Helpful article. Is it possible to run this utility with the ability to set which directory to list the file info? And to also to arrange the columns with appropriate header? Thanks.