Directory Viewer
A.First Edition
This is third assignment of comp229
6. [50%] System Calls
In this assignment you are going to call many system functions from a C program to look at
file information. In addition to the directory system calls in the program of Assignment 1,
you will use the
ctime and gmtime system calls from the standard library. Look at theonline man pages for these system calls for more information.
In this assignment, you are going to write a C program, say
mydv.c, which lets you viewthe files in a directory according to the specified options. Specifically, your program
(
mydv.c) should behave as follows:?
Display the prompt ?/FONT>mydv: ¡± (without the quotes) on the screen and wait for userinput (command).
?
If the user enters exit, your program should exit.?
If the user enters an empty line, mydv.c should simply display the prompt again (ona new line) and wait for user input.
?
If the user enters one of the following commands, mydv.c should do the specifiedfunction, and then it should display the prompt ¡°
mydv: ¡± (again, without the quotes)on a new line and wait for user input.
cd directory
Change the current working directory to directory by calling the function
ChangeDir
as described latter.dl [options]
List the files in the current working directory according to the specified
options (as in Assignment 2) by calling one or more of the functions
GetAllFiles
, SelectRange, SelectMonth, SelectDate,SelectBigger
, SelectSmaller, RemoveHidden, and PrintList asnecessary according to the specified options.
?
If the user enters any other command, mydv.c should create a new process andexecute the indicated command in this new process. When this new process exits,
mydv.c
should display its prompt on a new line and wait for user input.Specifically, when called as
dl option1 option2 option3 option4 option5
your
mydv.c program should do the following (notice that any of these options may beomitted).
?
The very first call to dl after a directory change invokes function GetAllFiles tocreate a list, say
fileinfo, of information (name, size, date of last modification) of allthe files in the current working directory, and all successive calls to
dl (until the nextcd
) use this fileinfo list to extract and print the files matching the specified options.?
Create the list of file pointers, filelist containing the indices to fileinfo for thefiles of interest (initially all the files in
fileinfo), in the current working directory. Ifthere are no files in
filelist, then print the following message and exit:Directory
dirname does not contain any file.?
Call functions SelectRange, SelectBefore, SelectAfter, SelectBigger,SelectSmaller
, and RemoveHidden, one by one to remove from filelist those fileswhich are not of interest depending upon the specified options. If any of these functions
returns 0, then print the following message and exit:
There are no files in
dirname satisfying the specifications: option1 option2 option3option4 option5
.?
Call the function PrintList to print the information about each of these files infilelist
(one per line) in the proper sorted order after the following header and exit.Directory
dirname contains the following files satisfying the specifications: option1option2 option3 option4 option5
.The output from your
mydv.c program should show for each file the following three fields(the fields are separated by three blanks) in a single line: (i) the name of the file (30
characters, left justified), (ii) the size of the file (8 digits, right justified), and (iii) the date of
last modification of the file in
mmm dd, yyyy; hh:mm:ss format. Notice that the file dateand time is stored internally as the number of seconds that have elapsed since January 1,
1970. You need to use functions
ctime and gmtime from the standard library to convertbetween the internal time and the calendar time. Look at the online man page for
ctimefor more information.
Following are the specifications of the necessary functions.
?
int ChangeDir (char *directory):Change the current working directory to
directory if it exists by calling the chdirsystem function (page 546) and return 1. If the specified directory does not exist,
print the following message
Directory
dirname does not exist.and return ¨C1.
?
int GetAllFiles ():This function sets up a table
fileinfo of 256 entries of containing the informationabout all the files (including hidden files but not subdirectories) in the current
working directory and returns the number of entries in
fileinfo. You shouldextract and modify the code from your debugged program of Assignment 1 to do this.
?
int SelectRange (char *begin, char *end):This function is called with two character strings ¡ª the beginning and end range of
file names. It removes from
filelist those files which are not in the specifiedrange and returns the number of files whose names are within the specified range.
?
int SelectDate (int date):This function is called with a date. It removes from
filelist those files which werenot modified on the specified date and returns the number of remaining files which
were modified on the specified date.
?
int SelectMonth (char *month):This function is called with a month. It removes from
filelist those files whichwere not modified during the specified month and returns the number of remaining
files which were modified during the specified month.
?
int SelectBigger (int size):This function is called with an integer size. It removes from
filelist those fileswhose size is smaller than specified size and returns the number of remaining files
whose size is equal to or greater than the specified size.
?
int SelectSmaller (int size):This function is called with an integer size. It removes from
filelist those fileswhose size is greater than the specified size and returns the number of remaining
files whose size is equal to or less than the specified size.
?
int RemoveHidden ():This function removes all the hidden files from
filelist and returns the number ofremaining files.
?
void PrintList (char *sortby):This function is called with a parameter specifying the required sort order (name,
size, time). It prints the information about the files in
filelist according to thespecified sort order.
Your output should include a listing of all your functions and main program and the output
for all test cases (at least for each of the specifications you used in Assignment 2) showing
that your
mydv.c program works as expected (as described above).You will also have to demo your program to the marker.
¡¡
C.Further improvement
//////////////////////////////////////////////////////////////////////////// //program: Assignment 3 of comp229 //author: Qingzhe Huang //ID: 5037735 //date: Oct. 24, 2003 //purpose of program: to use system call to implement "dv" directory viewer ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //features of program: //1. I used quite a few of string arrays, enum types even function arrays. //2. I used too much global variables as flag of states which is ugly. //limits of program: //1. The arguments for user-defined including "dl" and "cd" is between 2-11. // Any number of commands arguments will be regarded as system commands. //2. All 5 options---"-all", "-modified","-smallerthan","-biggerthan","-range"--- // can appear in any order and may or may not appear. //3. Sorting order is defined by last option: "-modified" by date, "-biggerthan" // and "-smallerthan" by size, the rest is by name. //4. Subdirectories won't be shown, including "." and "..". //5. Hidden files would be removed whenever "-all" is not present in commands. //6. Whenever "cd" is used successfully, all states start again. //7. When no files in list, it will not do selections by commands any more. //8. Once "cd" is recognized, parameters after second one are ignored. //////////////////////////////////////////////////////////////////////////////// #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <strings.h> #include <unistd.h> #include <dirent.h> #include <time.h> //#include <fcntl.h> extern int errno; //a record to store file info struct FileInfo { char name[31]; long size; time_t mdate; } fileInfo[256]; //the fileInfo counter int infoCount =0; //fileList stores the file index interested by user int fileList[256]={0}; //this is its counter int listCount =0; enum SortBy {ByName, ByDate, BySize}; //parameter for "PrintList()" to indicate what field to be sorted by char* sortedBy[3] = {"name", "date", "size"}; //the actual enum SortBy variable for index of "sortedBy[3]" int sortIndex = 0; //the parameter for "SelectRange()" char beginStr[2]; char endStr[2]; //flag for "GetAllFiles()", 1 means re-read all files which is //default, until set to 0 by "cd" parameter int reRead=1; //a simple way to change string to index, is it faster than MIA's little //switch function "MonToStr"? char* months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; //the command prompt for our "directory viewer" char* prompt = "mydv: "; //this is the directory name, cause I need to display several times //in different functions, I have to make it global. char buffer[256]; //these are all functions defined in assignment int SelectMonth(char* month); int ChangeDir(char* dir); int GetAllFiles(); int RemoveHidden(); int SelectRange(char* begin, char* end); int SelectDate(int date); int SelectBigger(int size); int SelectSmaller(int size); void PrintList(char* sortby); //these are my own defined utility functions //this check the command of "dl" and "cd" then send all rest //arguments to "checkOptions()" int checkCmd(char* cmd); //this will collect user input lines until "exit" int input(char* str); //check all options and call each "selection" functions by options accordingly int checkOptions(char** options, int count); //a utility function does the printing job int printInfo(); //three callback function for "qsort" int compName(const void*, const void*); int compDate(const void*, const void*); int compSize(const void*, const void*); //a function pointer array so as to be used in "qsort" int (*compFuns[3])(const void*, const void*) = {compName, compDate, compSize}; int main() { char str[256]; write(0, prompt, strlen(prompt)); //input will only return 0 unless "exit" met while (input(str)) { checkCmd(str); write(0, prompt, strlen(prompt)); } return 0; } int ChangeDir(char* dir) { int temp =0; if ((temp=chdir(dir))==-1) { printf("Directory %s does not exist.\n", dir); return -1; } else { reRead =1;//need re-Getallfiles return 1; } } int input(char* str) { char* ptr = str; while (1) { read(0, ptr, 1); if (*ptr==10) { break; } ptr++; } *ptr = '\0'; return strcmp(str, "exit"); } int GetAllFiles() { char fileName[256]; DIR *dp=NULL; struct dirent *d; struct stat s; //maybe MIA's way is simple---dir = "."; if (!(dp = opendir(getcwd(buffer, 256)))) { printf("%s\n", strerror(errno)); return -1; } //strcat(buffer, buffer[strlen(buffer)]=='/'?"":"/"); infoCount=listCount=0; while (d=readdir(dp)) { if (stat(d->d_name, &s)==-1) { printf("cannot access file %s\n", d->d_name); continue; } else { //we shall not select directories if (S_ISDIR(s.st_mode)) { continue; } } if (d->d_ino!=0) { //strcpy(fileInfo[infoCount].name, buffer); //printf("%s\n", d->d_name); if (stat(d->d_name, &s)!=-1) { strcpy(fileInfo[infoCount].name, d->d_name); fileInfo[infoCount].size = s.st_size; fileInfo[infoCount].mdate = s.st_mtime; infoCount++; fileList[listCount]=listCount; //means there is an index to... listCount++; } } } return infoCount; } int checkCmd(char* cmd) { char* ptr = cmd; //is there any limit for command line parameters? Yes, I said it is 20 //who would say no????:) char* options[20]; int count = 0, i; pid_t pid=0; //if user enters nothing, it is not NULL!!! if (!strcmp(cmd, "")) { return 0; } //\n should also be delimiter while (options[count]=strtok(ptr, " \n")) { ptr = NULL; count++; } //then we can pass options as char** options[count] = NULL; //just make sure it is null at end //the maximum and minimum of parameters if (count<=11&&count>=2) { if (!strcmp(options[0], "cd")) { //I won't check all other parameters return ChangeDir(options[1]);; } if (!strcmp(options[0], "dl")) { if (reRead) { GetAllFiles(); //make sure all files will be read only once with //multiple "dl" reRead =0; } //passing char** return checkOptions(&options[1], count-1); } } //fork another process to execute whatever user input if ((pid = fork())==0) { execvp(options[0], options); printf("%s\n", strerror(errno)); exit(-1); } //waiting utill user returns... wait(NULL); return 1; } int printInfo() { int i=0; char str[23]; struct tm* t; for (i=0; i<listCount; i++) { t = gmtime(&fileInfo[fileList[i]].mdate); sprintf(str, "%s %2d, %5d; %2d:%2d:%2d", months[t->tm_mon], t->tm_mday, t->tm_year, t->tm_hour, t->tm_min, t->tm_sec); printf("%-30s %8d %s\n", fileInfo[fileList[i]].name, fileInfo[fileList[i]].size, str); } } int checkOptions(char** options, int count) { int i=0; int result=0; int removeHidden=1; char string[256]; //make sure there is any file while (i<count&&listCount) { if (!strcmp(options[i], "-range")) { if (i+1<count) { //since it is only a character beginStr[0] = options[i+1][0]; beginStr[1] = '\0'; endStr[0] = options[i+1][2]; endStr[1] = '\0'; listCount=SelectRange(beginStr, endStr); i+=2; continue; } else { printf("%s\n", "missing parameter for -range options"); return -1; } } if (!strcmp(options[i], "-modified")) { if (i+1< count) { //this is for month listCount=SelectMonth(options[i+1]); i+=2; } else { printf("%s\n", "missing parameter for -modified options"); return -1; } if (i<count) { if (strcmp(options[i], "-all")&&strcmp(options[i], "-range") &&strcmp(options[i], "-biggerthan")&&strcmp(options[i],"-smallerthan")) { listCount=SelectDate(atoi(options[i])); i++; } } continue; } if (!strcmp(options[i], "-biggerthan")) { if (i+1<count) { listCount = SelectBigger(atoi(options[i+1])); i+=2; continue; } else { printf("%s\n", "missing parameter for -biggerthan options"); return -1; } } if (!strcmp(options[i], "-smallerthan")) { if (i+1<count) { listCount=SelectSmaller(atoi(options[i+1])); i+=2; continue; } else { printf("%s\n", "missing parameter for -smallerthan options"); return -1; } } if (!strcmp(options[i], "-all")) { removeHidden=0; i++; sortIndex = ByName; continue; } if (i==0) { printf("%s\n", "invalide parameter!"); return -1; } } if (removeHidden) { listCount = RemoveHidden(); } //if there is no more files, if (!listCount) { //I cannot understand why printf doesn't work properly //it won't display until the function returns, so I have to //use system call "write" which is very fast strcpy(string, "Directory "); strcat(string, buffer); strcat(string, " does not contain any files.\n"); write(0, string, strlen(string)); // printf("Directory %s does not contain any files.", buffer); } else { PrintList(sortedBy[sortIndex]); return result; } } int SelectMonth(char* month) { int i, temp=0; int imonth=0;//the month //find out the index of month for (i=0; i<12; i++) { if (!strcmp(month, months[i])) { imonth=i; break; } } for (i=0; i<listCount; i++) { if (gmtime(&fileInfo[fileList[i]].mdate)->tm_mon==imonth) { fileList[temp]=fileList[i]; temp++; } } listCount = temp; sortIndex = ByDate; return listCount; } int RemoveHidden() { int i, temp=0; for (i=0; i<listCount; i++) { if (fileInfo[fileList[i]].name[0]!='.') { fileList[temp]=fileList[i]; temp++; } } listCount=temp; return listCount; } int SelectBigger(int size) { int i, temp=0; for (i=0; i<listCount; i++) { if (fileInfo[fileList[i]].size>=size) { fileList[temp]=fileList[i]; temp++; } } listCount =temp; sortIndex = BySize; return listCount; } int SelectSmaller(int size) { int i, temp=0; for (i=0; i<listCount; i++) { if (fileInfo[fileList[i]].size<=size) { fileList[temp]=fileList[i]; temp++; } } listCount =temp; sortIndex = BySize; return listCount; } int SelectRange(char* begin, char* end) { int i, temp=0; char* ptr; for (i=0; i<listCount; i++) { if (fileInfo[fileList[i]].name[0]=='.') { ptr = fileInfo[fileList[i]].name + 1; } else { ptr = fileInfo[fileList[i]].name; } if (strcmp(ptr, begin)>=0 &&strcmp(ptr, end)<=0) { fileList[temp]=fileList[i]; temp++; } } listCount =temp; sortIndex = ByName; return listCount; } //this is mad! I already defined an enum type global variable to //indicate what should by sorted, however, I was forced to pass a //string instead of an enum index which I need to use a loop to find out!!! void PrintList(char* sortby) { int i=0; int (*comp)(const void*, const void*);//comp function pointer for (i=0; i<3; i++) { if (!strcmp(sortby, sortedBy[i])) { comp = compFuns[i]; break; } } qsort(fileList, listCount, sizeof(int), comp); printInfo(); } //the help for UNIX is so BAAAAAAAAAAD that they give a wrong example //which won't work under gcc which doesn't allow modify const pointer!!!! int compName(const void*first, const void*second) { int* pi = first, *pj = second; int i = *pi; int j = *pj; return strcmp(fileInfo[i].name, fileInfo[j].name); } int compDate(const void*first, const void*second) { int *pi = first, *pj=second; long i=fileInfo[*pi].mdate; long j=fileInfo[*pj].mdate; if ( i< j) { return -1; } else { if (i>j) { return 1; } else { return 0; } } } int compSize(const void*first, const void*second) { int *pi = first, *pj=second; int i=fileInfo[*pi].size; int j=fileInfo[*pj].size; if ( i< j) { return -1; } else { if (i>j) { return 1; } else { return 0; } } } int SelectDate(int date) { int i, temp=0; for (i=0; i<listCount; i++) { if (gmtime(&fileInfo[fileList[i]].mdate)->tm_mday==date) { fileList[temp]=fileList[i]; temp++; } } listCount = temp; sortIndex = ByDate; return listCount; }