Name: list.c
Author: guozan _SCS_BUPT
Mail: guozan523@foxmail.com
Date: 2010/4/6
實驗目的:練習vi,使用UNIX的系統調用和庫函數,體會UNIX文件通配符的處理方式以及命令對選項的處理方式。
編程實現程序list.c,列表普通磁盤文件(不考慮目錄和設備文件等),列出文件名和文件大小。
與ls命令類似,命令行參數可以有0到多個
0個參數:列出當前目錄下所有文件
參數為普通文件:列出文件
參數為目錄:列出目錄下所有文件
實現自定義選項r,a,l,h,m以及--
r 遞歸方式列出子目錄
a 列出文件名第壹個字符為圓點的普通文件(默認情況下不列出文件名首字符為圓點的文件)
l 後跟壹整數,限定文件大小的最小值(字節)
h 後跟壹整數,限定文件大小的最大值(字節)
m 後跟壹整數n,限定文件的最近修改時間必須在n天內
-- 顯式地終止命令選項分析
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
/*
slective options about ls
rflag is about recursive
aflag is about ones with . infront
lflag is about the minimum size
hflag is about the maximum size
mflag is about the modified time
*/
int rflag, aflag, lflag, hflag, mflag;
long modified_time; //the last time file be modified, days ago
off_t lower_size; //file's minimum size
off_t upper_size; //file's maximum size
/*
set the flags, thus the ls option
*/
void getoptions(int argc, char *argv[])
{
char ch;
//clear, all unseted
rflag = 0; aflag = 0; lflag = 0; hflag = 0; mflag = 0;
//use getopt to get the options, want to know more, call man
//the last one or after -- was set in argv[optind]
while ((ch = getopt(argc, argv, "ral:h:m:")) != -1) {
switch (ch) {
case 'r': rflag = 1; break;
case 'a': aflag = 1; break;
case 'l': lflag = 1; lower_size = atol(optarg); break;
case 'h': hflag = 1; upper_size = atol(optarg); break;
case 'm': mflag = 1; modified_time = atol(optarg); break; //get days
case '?': printf("Unknown option: %c\n", (char)optopt); break;
default : printf("Step into default\n"); break;
}
}
}
/*
the function to list things in path
*/
int ls(char *path)
{
struct stat st; //for check this is a directory or file
char temp[100]; //if path is null, it is used to get current directory
// get the path
if (path == NULL || path[0] == '-') {
path = temp;
getcwd(path, 100);
}
/* open the inode of file */
if (lstat(path, &st)) {
fprintf(stderr, "Error: %s not exist.\n", path);
return (-1);
}
/* judge whether the file is a file or a directory */
if (S_ISDIR(st.st_mode)) {
ls_dir(path);
}
else if (S_ISREG(st.st_mode)) {
print(path);
}
else {
printf("Not ordinary file, wouldn't be listed.\n");
}
return 0;
}
/*
list dirs, may recursively or not, depending on rflag
one thing is sure that it will list directories and files first,
then consider the things in the directories
*/
int ls_dir(char *path)
{
DIR *dp = NULL;
struct dirent *dirp = NULL;
if (path[0] != '.' || (path[0] == '.' && aflag == 1)) {
printf("\n%s:\n****************************************\n", path);
/* open the directory */
if ((dp = opendir(path)) == NULL) {
fprintf(stderr, "Error: can't open directory %s!\n", path);
return (-1);
}
chdir(path);
/* list all the things in directory */
while ((dirp = readdir(dp)) != NULL) {
print(dirp->d_name);
}
/* recursively ls dirs, after ls things together,
it's time to list things in children directory */
if (rflag == 1) {
rewinddir(dp); //reset dp
while ((dirp = readdir(dp)) != NULL) {
if (strcmp(dirp->d_name, ".") == 0
|| strcmp(dirp->d_name, "..") == 0) { //no current and parent directory
continue;
}
ls_dir_r(dirp->d_name); //only list directories, judged inside the function
}
}
/* close the directory */
if (closedir(dp)) {
fprintf(stderr, "Error: can't close the directory %s!\n", path);
return -1;
}
chdir("..");
}
return 0;
}
/*
list directories recursively,
only directories, nomatter what path you put in
*/
int ls_dir_r(char *path)
{
struct stat st;
/* open the inode of file */
if (lstat(path, &st)) {
fprintf(stderr, "Error: %s not exist.\n", path);
return (-1);
}
/* only ls directories */
if (S_ISDIR(st.st_mode)) {
ls_dir(path);
}
}
/*
print the filetype/size/name on the screen
*/
int print(char *path)
{
struct stat st;
time_t tp;
char *filename = NULL;
//get current time
time(&tp);
if (lstat(path, &st)) {
fprintf(stderr, "Error: %s can't be opened.\n", path);
return (-1);
}
/* get file name */
if ((filename = strrchr(path, '/')) != NULL) {
filename++;
}
else {
filename = path;
}
/* judge whether to list the file */
if ((S_ISDIR(st.st_mode)|| S_ISREG(st.st_mode)) //only directories and normal files
&& (lflag == 0 || (lflag == 1 && (st.st_size >= lower_size))) //the min size
&& (hflag == 0 || (hflag == 1 && (st.st_size <= upper_size))) //the max size
&& (mflag == 0 || (mflag == 1 && ((tp - st.st_mtime) <= modified_time * 24 * 60 * 60))) //modified time
&& (aflag == 1 || (aflag == 0 && filename[0] != '.')) //file with a '.' infront
) {
printf("%s\t%10ld\t%s\n", (S_ISDIR(st.st_mode) ? "DIR": "FILE"), st.st_size, filename);
}
return 0;
}
/*
The main function
*/
int main(int argc, char *argv[])
{
getoptions(argc, argv);
ls(argv[optind]);
return 0;
}