nice programs there, however it differs from what real du command outputs, i made a modification which matches what du command output, however, it only includes one -k option. now it takes a file or a directory. also, it can take no argument which by default it will be current directory, and it takes -k option which only display half size. lastly, i includes a small feature which when the sub directories go beyond 4 it will stop and print message, because we don't want to print a very unacceptable long path directory info.
Code:
#define NONE 0
#define ALL 1
#define SUM 2
#define F 3
#define G 4
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
int optS( char* );
int noOpt( char*, int,char* );
int optK(char* , int,char*);
int fopt( char* );
int main( int argc, char *argv[] )
{
int c,type=NONE,lvl=0,blocksize=0;
char ck[1000];
struct stat info;
if (argc ==1) /* no argument */
{type = ALL;}
if (argc ==2)
{
strcpy(ck, argv[1]);
if(lstat(ck, &info) < 0)
{printf( "Unable to stat: %s \n", ck);
exit(1);}
if(S_ISDIR(info.st_mode) == 0) /* it's a file */
{
type = F;
}
}
while( (c = getopt(argc, argv, "+k")) != -1 ) /*take option */
{
switch( c )
{
case 'k': /* option k */
strcpy(ck, argv[2]);
if(lstat(ck, &info) < 0)
{printf( "Unable to stat: %s \n", ck);
exit(1);}
if(S_ISDIR(info.st_mode) == 0) /* if it's a file */
{type = G;}
else if( type == NONE )
type = SUM;
else {
return EXIT_FAILURE;
}
break;
default:
return EXIT_FAILURE;
}
}
switch( type )
{
case ALL:
noOpt(".", lvl,NULL); /*no argument, so current dir is default setting*/
break;
case SUM:
while( optind < argc ) /*directory is taking option -k */
optK( argv[optind++], lvl, NULL );
break;
case NONE:
while( optind < argc ) /* normal one argument, directory*/
noOpt( argv[optind++], lvl,NULL );
break;
case F:
while( optind < argc ) /*argument is a file*/
{
if( (blocksize=fopt(argv[optind])) != -1 )
printf( "%d%s%s\n", blocksize, "\t ", argv[optind++] );
}
break;
case G:
while( optind < argc ) /*argument is a file and take -k option*/
{
if( (blocksize=fopt(argv[optind])) != -1 )
printf( "%d%s%s\n", blocksize/2, "\t ", argv[optind++] );
}
break;
}
return EXIT_SUCCESS;
}
/************************************************
Function optS
calculate total blocksize and return value
*************************************************/
int optS( char *dpath )
{
DIR *pDir;
struct dirent *dInfo;
struct stat fInfo;
char tempName[1000];
int blocksize = 0;
if( (pDir = opendir(dpath)) == NULL) /*see if can stat or not*/
{
perror("cannot open");
return 0;
}
while( (dInfo=readdir(pDir)) != NULL )
{
if( strcmp(dInfo->d_name, ".") != 0 && strcmp(dInfo->d_name, "..") != 0 ) /*ignore .. and . */
{
strcpy( tempName, dpath );
strcat( tempName, "/" );
strcat( tempName, dInfo->d_name );
if ((lstat(tempName,&fInfo)) == -1)
printf( "Unable to lstat: %s\n", dInfo->d_name);
else if( S_ISDIR(fInfo.st_mode) ) /*accumulate size and add directory size*/
{blocksize += fInfo.st_blocks;
blocksize += optS (tempName);}
else
blocksize += fInfo.st_blocks; /*accumulate blocksize*/
}
}
closedir( pDir );
return blocksize;
}
/************************************************
function noOpt
normal directory argument
************************************************/
int noOpt( char *dpath, int lvl,char *temp )
{
DIR *pDir;
struct dirent *dInfo;
struct stat fInfo;
char tempName[1000],tempchar[1000];
if( (pDir = opendir(dpath)) == NULL )
{
perror("cannot open");
return 1;
}
while( (dInfo=readdir(pDir)) != NULL )
{
if( strcmp(dInfo->d_name, ".") != 0 && strcmp(dInfo->d_name, "..") != 0 )
{
strcpy( tempName, dpath );
strcat( tempName, "/" );
strcat( tempName, dInfo->d_name );
if( lstat(tempName, &fInfo) == -1 )
printf( "Unable to stat: %s \n", tempName );
else if( S_ISDIR(fInfo.st_mode) ) /*if it's a nested directory loop through*/
{
strcpy(tempchar, dInfo->d_name);
if ( lvl > 2) /*set up a counter to monitor how many directory go through*/
{printf("encounter a deep path unable to print : %s.\n",temp);/*print message*/
return 0;
}
noOpt( tempName, lvl+1,tempchar );
}
}
}
printf("%d%s%s\n", 2+optS(dpath), "\t", dpath); /* print final outcome for every loop*/
return 0;
}
/**************************************************
function optK
take directory as argument and take -k option
**************************************************/
int optK(char *dpath, int lvl,char *temp )
{
DIR *pDir;
struct dirent *dInfo;
struct stat fInfo;
char tempName[1000], tempchar[1000];
if( (pDir = opendir(dpath)) == NULL )
{
perror("cannot open");
return 1;
}
while( (dInfo=readdir(pDir)) != NULL )
{
if( strcmp(dInfo->d_name, ".") != 0 && strcmp(dInfo->d_name, "..") != 0 )
{
strcpy( tempName, dpath );
strcat( tempName, "/" );
strcat( tempName, dInfo->d_name );
if( lstat(tempName, &fInfo) == -1 )
printf( "Unable to stat: %s \n", tempName );
else if( S_ISDIR(fInfo.st_mode) )
{
strcpy(tempchar, dInfo->d_name);
if ( lvl > 2) /*set up a counter to monitor how many directory go through*/
{printf("encounter a deep path unable to print : %s.\n",temp);/*print message*/
return 0;
}
/*loop through all directory inside */
optK( tempName, lvl+1,tempchar);
}
}
}
lvl = 0; /* clear it after loop*/
printf("%d%s%s\n", (2+optS(dpath))/2, "\t", dpath); /*the size is half of regular*/
return 0;
}
/************************************************
function fopt
take argument as file
*************************************************/
int fopt(char *dpath)
{
char tempName[1000];
int blocksize = 0;
struct stat fInfo;
strcpy( tempName, dpath );
if ((lstat(tempName,&fInfo)) == -1)
printf( "Unable to lstat: %s\n", tempName);
else
blocksize = fInfo.st_blocks;
return blocksize;
}