In linux, there are 7 types of files: common files, directories, link files, character device files, block device files, socket files, and fifo files. In general, we should be able to guess the most common and directory files, but what is the specific data?
I. Key Points of knowledge
Two things are required to achieve this purpose:
1) Identify the file type
The information of a file is encapsulated into a struct:
struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device ID (if special file) */ off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for filesystem I/O */ blkcnt_t st_blocks; /* number of blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last status change */ };
The st_mode member records the file type. You can use macros such as S_ISREG (mode) to identify the type.
The following functions are required to obtain the File status information:
int stat(const char *path, struct stat *buf); int fstat(int filedes, struct stat *buf); int lstat(const char *path, struct stat *buf);
The differences between lstat () and stat () are mainly for linked files. stat () returns the information of the files to which the linked files point, while lstat () is for the linked files themselves.
2). traverse the directory
When directory traversal is performed, there is another struct to return the node file obtained through traversal.
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 */ char d_name[256]; /* filename */ };
The d_name member contains the name information of the current node item, And the d_type member contains the file type information of the current node item. (In fact, this type of information is enough for the statistics file type. You do not need to use the file information mentioned above to read the function)
The following functions are required to traverse a directory:
struct dirent *readdir(DIR *dir);DIR *opendir(const char *name);int closedir(DIR *dir);int chdir(const char *path);int fchdir(int fd);
Ii. Example
The complete procedure is as follows:
//this program is work for produce count of the type of files.//i.e: normal file, directory, symbolic file, device file and so on.#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <stdio.h>#include <sys/types.h>#include <dirent.h>//type of filestypedef enum FileType {TYPE_LNK,TYPE_REG,TYPE_DIR,TYPE_CHR,TYPE_BLK,TYPE_FIFO,TYPE_SOC,TYPE_ERR,TYPE_CNT,}FILETYPE;static unsigned long count[TYPE_CNT];//count of the type of filestatic int recur = 0;//the depth of recursionstatic int recur_max;//tha max value of recursion depthtypedef int ( * FUNC) ( char *pathname);static int inline recalRecurMax( int recur, int *recur_max){return *recur_max = *recur_max<recur?recur:*recur_max;}//identify the type of a filestatic int file_type( char *pathname){intret;struct statbuf;ret = lstat( pathname, &buf);//could't use stat(), because of the link file .if( ret<0){perror(" ");return TYPE_ERR;}FILETYPE type;switch( (buf.st_mode&S_IFMT) ){case S_IFLNK:type = TYPE_LNK;break;case S_IFREG:type = TYPE_REG;break;case S_IFDIR:type = TYPE_DIR;break;case S_IFCHR:type = TYPE_CHR;break;case S_IFBLK:type = TYPE_BLK;break;case S_IFIFO:type = TYPE_FIFO;break;case S_IFSOCK:type = TYPE_SOC;break;default :type = TYPE_ERR;}return type;//return the type of this file}static int ftw( char *rootpath, FUNC callback){recur++;recalRecurMax( recur, &recur_max);//record the max value of recursion depthDIR*pdir;pdir = opendir( rootpath);//open this directoryif( NULL==pdir ){perror(" ");return 0;}int ret;ret = chdir( rootpath);//enter this directoryif( ret<0){perror(" ");return 0;}struct dirent*pdirent;do{pdirent = readdir( pdir);//be carefull, this function will traverse all files in this directory.if( NULL!=pdirent){int type;type = callback( pdirent->d_name );//count the type of file//printf("%s, %d\n", pdirent->d_name, type);count[type]++;if( (DT_DIR==pdirent->d_type)//enter sub-directory&&(strcmp( pdirent->d_name, ".") )!=0&&(strcmp( pdirent->d_name, ".."))!=0 ){int ret;ret = ftw( pdirent->d_name, callback);if( !ret)printf("error: %s is not a valid path\n", pdirent->d_name);}}}while( NULL!=pdirent );chdir("..");closedir( pdir);recur --;return 1;}static void show( unsigned long count[]){double sum=0;inti;for( i=0; i< TYPE_CNT; i++){sum+= count[i];}printf( "LNK: %ld --%%%f\n", count[TYPE_LNK], count[TYPE_LNK]*100/sum);printf( "REG: %ld --%%%f\n", count[TYPE_REG], count[TYPE_REG]*100/sum);printf( "DIR: %ld --%%%f\n", count[TYPE_DIR], count[TYPE_DIR]*100/sum);printf( "CHR: %ld --%%%f\n", count[TYPE_CHR], count[TYPE_CHR]*100/sum);printf( "BLK: %ld --%%%f\n", count[TYPE_BLK], count[TYPE_BLK]*100/sum);printf( "FIFO: %ld --%%%f\n", count[TYPE_FIFO], count[TYPE_FIFO]*100/sum);printf( "SOC: %ld --%%%f\n", count[TYPE_SOC], count[TYPE_SOC]*100/sum);printf( "ERR: %ld --%%%f\n", count[TYPE_ERR], count[TYPE_ERR]*100/sum);printf(" recur_max = %d\n", recur_max);}int main( int argc, char *argv[]){if( 2!=argc ){printf("usage: a.out <pathname>\n");return 0;}intret;ret = ftw( argv[1], file_type);show( count);if( !ret)printf(" %s is not a valid path\n", argv[1]);return 0;}
Of course, there are actually many simple ways to complete this function, such as ftw () and other functions.
After running the above program in your system, the result is as follows:
[root@localhost ftw]# ./interesting.out /LNK : 19448 --%4.339260REG : 330217 --%73.678398DIR : 98236 --%21.918530CHR : 152 --%0.033914BLK : 47 --%0.010487FIFO : 4 --%0.000892SOC : 83 --%0.018519ERR : 0 --%0.000000 recur_max = 14