/* Filename: list.c Author: guozan @SCS-BUPT Mail: guozan523@gmail.com Date: 2010/4/6 Desciptions: a program similar with linux's ls, with -a : list all, include ones with . infront -r : recursively ls -l : the minimum size of file to list -h : the maximum size of file to list -m : the last modified time till now, in day More: v0.2 : modified the morning about 0:18 2010/4/7 by guozan print more beautiful, such as print the absolute path, and align better */ #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; char temp[100]; //used to store the absolute path 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); // get the path getcwd(temp, 100); printf("/n%s:/n****************************************/n", temp); /* 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; } lsdir_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 lsdir_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/t": "FILE"), st.st_size, filename); } return 0; } /* The main function */ int main(int argc, char *argv[]) { getoptions(argc, argv); ls(argv[optind]); return 0; }