CPS 6: Lab #6

Summer 1999

Directories via Recursion and Vectors

6 points

Due Tuesday - June 15 - 11:59pm

Change into your "cps6" directory using the "cd" command and create another directory called "lab6" using the "mkdir" command. Change into the "lab6" directory. If you did this correctly, when you type "pwd" you should see a long path name that ends with "/cps6/lab6"

In order to do this lab, you need to copy some files using the following "cp" (for "copy") command (don't forget the trailing period, or dot):

       cp  ~dr/cps6/lab6/*  .

If you type "ls" to list the files now in your lab6 directory, you should see the following files: Makefile and subdir.cc.

For each of the programming problems that follow, you should use the style rules discussed in class, which includes indentation, meaningful variable names and comments at the top of the file and for each function.

Part 1 - Shellscript

A shellscript is a file with UNIX commands that you can create and execute. Using emacs, create a file named "previous" and put the following unix commands in it. The "echo" command prints whatever is between the quotes to the screen.

    cd  ..
    echo "listing files in parent directory ..."
    ls
    echo "Done"

To execute a shellscript, just type the name of the file. Type: previous

It won't work yet, you should receive the error message: Permission denied.

You'll need to make the file an executable file in order to execute it. Emacs by default makes a file nonexecutable. Use the chmod command to change a file to executable, type:

 
    chmod  u+x  previous

This command gives the (u)ser permission to e(x)ecute the file. Now try to execute the file by typing: previous

This executable file should execute the UNIX commands one by one and list the files in the parent directory of your current directory.

Show one of the TA's the following:

  1. Show the TA how to execute the file previous
  2. Show how to echo your name to the screen.

Part 2 - Processing Directories

This part provides practice with using classes and recursion, and may help you find large files you can remove to ease quota problems.

Compile the program subdir.cc. You may get compiler warnings, but that's OK. Run the program and enter the name of your directory. You can type a dot `` . '' for the current directory, or you can type the complete path which is similar to /afs/acpub.duke.edu/users/d/r/dr , but the letters may be different and use your login instead of dr (type "pwd" to see your pathname). This will print a listing of all your files and subdirectories. This can take a long time if you have many directories. You'll make a few changes to this program so that it will print the size of each file/subdirectory. If you run the program a second time it will be MUCH FASTER. This is because the file query information has been cached on the computer you're using.

DirStream and DirEntry classes

The DirStream and DirEntry class are classes for manipulating directories. The DirEntry class provides directory information such as the name and size of a directory and the DirStream class is an iterator for processing all the files in a directory. The relevant member functions for these two classes that you will need for this assignment are shown below.

class DirEntry
{
  public:
    DirEntry();           // constructor
    
    string Name();        // return name (not full path) of file
    int Size();           // return size (bytes) of file
    bool IsDir();         // return false if file, true if directory
    
  // rest not shown
};


class DirStream
{
  public:
    DirStream();                     // current directory
    void open(const string & name);  // open, bind to file with name
    bool fail();                     // return true if failed, else false

    void First();                    // standard iterator functions
    void Next();
    bool IsDone();
    DirEntry Current();              // returns current Directory entry
 // rest not shown   
};

Modification: Sizes of files/directories

The function ProcessDir currently creates a DirStream and DirEntry and iterates through all files in the current directory, printing the name of the file and if the file is a subdirectory, then recursively processing the files in this subdirectory.

In this part, modify the function ProcessDir to return the total size of all files and subdirectories in a directory.

  1. Change the return type of the function ProcessDir from void to int . The function should return the size of all the files in the directory specified by the parameter s .

  2. In addition, the size of each individual file will be printed before the name of the file.

    To do this, use the member function Size() for the DirEntry variable entry . Print the size before the name of the file:

         cout << entry.Size() << "\t" << entry.Name() << endl;
    

  3. You should also define an int variable initialized to 0 (define it after entry is defined in ProcessDir ). This variable will be used to accumulate the size of all files in a given directory as well as the sizes of files in subdirectories. This value will be returned by ProcessDir . Make sure you increment this variable by the size of each file processed in a directory, plus by the return value of the recursive call to ProcessDir.

  4. Finally, you'll need to return a value. The last statement of the function, after the if statement , should return the total size of all files in the directory (and its subdirectories).

  5. In the function main you should define an integer variable to use for the value returned by ProcessDir . After calling ProcessDir, print the total size of all files in the directory and its subdirectories.

After making these changes, compile and run your program. Use the name of your own directory as input. How big is this directory? (Note: the counts may not be precisely correct, but are fairly accurate). How big is the directory /afs/acpub.duke.edu/users15/rodger/cps6?

If you see files that are larger than 200000 bytes you should check to see if these files are executables. If so, you should remove them since they will contribute to your quota limit. Since you can always recompile the source code to generate the executables, you don't need to keep the executables around.


Part 3 - Vectors/Arrays and Largest Files

Copy the file subdir.cc to mydir.cc using
    cp subdir.cc mydir.cc

You'll modify the file mydir.cc so that each file name and its size is placed in an array as it is printed. To do this follow the steps below.

Compile your program and make sure it runs correctly.


Extra Credit (2 pts)

Copy the file mydir.cc to mydirX.cc using
    cp mydir.cc mydirX.cc
You'll modify the file so that a specified number of largest files stored in the Vector will be printed, from largest to smallest.

  1. Before the call to MaxPrint in the main function, ask the user how many names of files of largest size should be printed.

  2. Modify MaxPrint to pass an additional integer indicating the number of filenames of largest size to print, and then print these from largest size to smallest size. Do not modify the Vector passed to MaxPrint! .

The output after printing all the files might look something like (4 largest files in a directory, ordered by size):

How many largest files to print? 4
anim 779956
subdir 367752
olamedium.gs.Z 97053
mys.pbm.Z 35402

Submission

When your programs for parts 2 and 3 compile and produce the correct output, create a README file. This file should include your name, section number, the date, how long you worked on these programs, and anyone you received significant help from. You can then turn everything in by typing (mydirX.cc is omitted if you did not do the extra credit):

         submit6 lab6 README subdir.cc mydir.cc mydirX.cc

You should receive a message telling you that the programs were submitted correctly.