File System (fs) Project
COP-3402
Table of Contents
1. Overview
In this project, you will implement a variation of the find
and wc
commands called myfind
. This tool will recursively list out all files in the source tree (in any order).
2. Input
USAGE: myfind [-l] path EXAMPLES: myfind file.c myfind dirfile myfind dirfile/file.c myfind dirfile/subdir/file myfind -l dirfile/subdir/file.c
The program should be called myfind
. It takes one argument and one optional flag. path
is any absolute or relative path. If a non-directory file is given, it will only list that one file. A directory file will have all files in its directory listed and recursively follow any subdirectories
Add a flag "-l" to list out the number of lines (number of '\n' characters) in regular file
2.1. Error conditions
In the following cases, exit immediately with EXIT_FAILURE
:
- If there are no arguments to the program
- If there are two arguments but the first is a not the "-l" flag.
In the following cases, skip printing the file
- The file or directory doesn't exist, lacks necessary permissions, or cannot be opened, read, and closed for any other reason
3. Output
The output should be a list of the paths to each file to standard out, starting with the input path given as the command-line argument. If the -l
flag is set, then the number of lines in the file as a integer should be printed after the filename, separated by a tab \t
(see Format strings for the exact strings to use for printing output).
3.1. Example
If a construct a new directory tree like this
mkdir contents mkdir contents/subdir touch contents/file1 echo -ne "1\n2\n3" > contents/file2 echo -ne "1\n2\n3\n4\n" > contents/subdir/file3
and then run myfind
on it like this:
./myfind -l contents
I should see the following output:
contents contents/subdir contents/subdir/file3 4 contents/file2 2 contents/file1 0
Where the space between the file name and the number of lines is a single tab character (\t
).
See Grading for some automated test cases.
4. Implementation
For each file in the file tree starting from path
:
- If it's a directory file, list its name, then recurse over each file in the directory, except for
.
and..
. Note that the tool should accept . or .. as arguments to the tool. Just be sure not to recursively traverse these directories.) - If it's a regular file, list its name, then also list the number of lines in the file, i.e., the number of newline characters (
'\n'
) - If it's any other kind of file, list its name only
- If the file doesn't exist, or cannot be open, etc., skip it
Error messages are optional, but should only be written to stderr, not to stdout, which will be used for program output, i.e., use fprintf(stderr, ...)
instead of printf
.
4.1. Format strings
File Type | Format String |
---|---|
Regular (no -l) | "%s\n" |
Regular (with -l) | "%s\t%ld\n" |
Directory | "%s\n" |
Other | "%s\n" |
Be sure to print the entire path for each file, i.e., the given path argument joined with the path separator character ("/").
4.2. System call and library references
Do not use helper libraries or other simplified calls to achieve similar results as functions below. Just use the syscalls or library functions below for these aspects of the project.
Symbol | Reference | Reading |
---|---|---|
stat() | man 2 stat |
LPI 15.1 |
struct stat | man 3 stat |
|
st_mode | man 7 inode |
|
opendir() | man 3 opendir |
LPI 18.8 |
readdir() | man 3 readdir |
|
closedir() | man 3 closedir |
|
struct dirent * | man 3 readdir |
|
open() | man 2 open |
LPI 4.1 |
read() | man 2 read |
|
write() | man 2 write |
|
close() | man 2 close |
|
perror() | man 3 perror |
LPI 3.4 |
exit(EXIT_FAILURE) | man 3 exit |
man
is the command-line manual.- LPI is The Linux Program Interface book.
- Knowledge of memory management and string processing is assumed.
4.3. Example header files
These are a set of header files that is sufficient for completing the project:
#include <fcntl.h> // O_RDONLY, O_WRONLY, O_CREAT, open #include <errno.h> // errno #include <stdio.h> // perror, fprintf #include <dirent.h> // opendir, readdir, DIR, struct dirent #include <stdlib.h> // exit #include <sys/stat.h> // stat #include <assert.h> // assert #include <string.h> // string.h #include <unistd.h> // read, write, close #include <stdbool.h> // bool
4.4. Joining paths
Be sure when concenating strings for the paths that you malloc enough space for the entire new string plus the additional path separator and plus the null terminator for the string, e.g.,
// len + separator + len + terminator int concatlen = strlen(curpath) + 1 + strlen(curdir->d_name) + 1; char *newpath = malloc(concatlen * sizeof(char)); if (NULL == newpath) { perror("malloc"); exit(EXIT_FAILURE); } snprintf(newpath, concatlen, "%s/%s", curpath, curdir->d_name);
The grading tests will not put a path separator character at the end of the path, even if its a directory. In testing, if you do have a path separator, then joining by string concanetion may result in a double path separator, e.g., subdir//file, which should be harmless.
5. Building and running the tool
Create a Makefile that will build your project and give the resulting program the name myfind
. See the hello project for an example Makefile.
Your project must be buildable with make
and runnable with ./myfind
, both from the root of your repo, i.e.,
cd ~/cop3402fall25/fs make ./myfind
Automated grading will build and run your tool this way and only this way.
6. Submitting your project
6.1. git
setup
Be sure to complete the vc exercise before attempting this project.
Create a new local repository, following the directions in the vc exercise (including the git --set-upstream
last step) and set the local and remote repository URLs to be the following locations:
Local repository | ~/cop3402fall25/fs |
Remote repository | gitolite3@eustis3.eecs.ucf.edu:cop3402/$USER/fs |
Commands
These steps only setup the repo, do not submit your code, and assume you have already completed the vc exercise. Consult that exercise for specifics on validating each step and submitting your code.
mkdir -p ~/cop3402fall25/fs cd ~/cop3402fall25/fs git init echo "fs project" > README.md git add README.md git commit README.md # Enter a commit message in the editor that pops up git remote add submission gitolite3@eustis3.eecs.ucf.edu:cop3402/$USER/fs git push --set-upstream submission master
6.2. Self-check
See the hello project for instructions on cloning a project from the grading server.
7. Bonus features
7.1. Implement a file type filter
Implement a file type filter option. This option will either limit the results to either only regular files or only directory files. The option will either be --type f
to limit to only regular files or --type d
to limit to only regular files. Without this option, there should be no filtering as in the non-bonus project requirements. Here is an example:
Take the following directory structure, where dir1
and dir2
are directory files while file1
, file2
, and file3
are regular files:
. ├── dir1 │ ├── file1 │ └── file2 ├── dir2 └── file3
Running ./myfind --type f .
should yield the following (in any order):
./file3 ./dir1/file2 ./dir1/file1
Running ./myfind --type d .
should yield the following (in any order):
. ./dir2 ./dir1
7.2. Notes
- These options will require allowing for up to three arguments by the tool without exiting with an error. This won't affect scoring, since this isn't tested.
- Be sure to allow any ordering of options, i.e.,
--type
, and-l
may appear in any order. - Note that
argv
will have two separate array slots for the option name and the parameter to that name, e.g.,-type
andf
may beargv[1]
andargv[2]
respectively. These indices may differ depending on the order of options given by the user on the command-line). - You may use the getopt library if you want to make option processing easier.
- Bonus points will be graded mechanically, but test cases will not be released. Please develop your own test cases and use the examples given above.
- The file type is not its extension. Where can we see whether the file is a regular file or a directory file?
- The non-bonus requirements for recursively traverses subdirectories and using
-l
still apply.
8. Grading
The test cases used to grade the project are listed below. Scripts to run the the odd-numbered test cases are provided publicly, while the even-numbered test cases are private.
To use the automated tests, first download them, e.g.,
cd ~/cop3402fall25/fs wget https://www.cs.ucf.edu/~gazzillo/teaching/cop3402fall25/files/fs_public_tests.tar tar -xvf fs_public_tests.tar
To run a test case, e.g., tests/03.sh
, use the following bash command from the root of your local repository directory:
bash fs-tests/03.sh $(realpath myfind) echo $?
This runs the bash script, passing in the absolute path to your program, which is what $(realpath myfind)
does. The result of echo $?
should be 0
which indicates the test was succesful.
8.1. Test cases
# | Description | Expected Output |
---|---|---|
1 | Call myfind with no arguments | It should fail with the appropriate exit code. |
2 | Call myfind with an invalid option (not -l) | It should fail with the appropriate exit code. |
3 | Call myfind with a single empty file | It should print the file name |
4 | Call myfind with a path to an empty directory | It should only print the directory path |
5 | Call myfind with a path to a directory with no subdirectories | It should print the directory path and paths to all files in the directory |
6 | Call myfind with a path to a directory containing a subdirectory | It should recursively print the directories' paths and their contents |
7 | Call myfind with . | It should print . and all its contents |
8 | Call myfind with .. | It should print .. and all its contents |
9 | Call myfind with -l on a single file | It should print the file path and number of lines in the file |
10 | Call myfind with -l on a directory containing nested files and directories | It should recursively print the directory and contents with lines for regular files |
9. Grading schema
Criterion | Points |
---|---|
The git repo exists | 1 |
The program is written, builds, and runs as described here | 1 |
Tests pass, prorated by the number of test cases passing | 6 |
TOTAL | 8 |