Scanning Directories in a Shore Application
Version 0.1

The Shore Project Group
Computer Sciences Department
UW-Madison
Madison, WI

1 Introduction

The DirScan class provides a convenient interface for scanning directories. This document describes how to use the DirScan class. The Shore release includes a simple example program called shls (``Shore ls''), that illustrates the use of the DirScan class. Shls can be found in the examples/shls directory of the Shore release.

2 The DirScan Class

An application scans a directory by creating a DirScan object. DirScan objects are transient C++ objects, not persistent Shore objects. A DirScan object can be in one of two states: open or closed. A scan must be opened inside a transaction, and can only be used inside the transaction in which it was opened. Once a scan is opened, it stays open until it is explicitly closed, or until the scan object is destroyed, or the transaction terminates. This means, for example, that the scan object remains open even after the end of the scan has been reached, or if an error condition has been encountered.

Directory scans request blocks of directory entries from the Shore server and store them in a buffer. Applications can set the size of this buffer, although the size must be at least DEF_DIRSCAN_BUFSIZE to ensure that the buffer is large enough to hold at least one directory entry. If a smaller buffer size is requested, it will be rounded up to the default size.

A scan of a directory returns some number of DirEntry structures. The DirEntry type (defined in OCTypes.h) looks like this:


    struct DirEntry
    {
        LOID loid;
        int namelen;
        char name[MAXNAMLEN + 1];
    };

The fields of the structure are:

namelen
The length of the name field.

name
The null-terminated name of the entry. This name is only the portion of the pathname stored in the directory; it is not a complete pathname.

loid
The logical OID associated with the directory entry.

The public portion of the DirScan class is defined as follows:


    class DirScan
    {
     public:

        DirScan();
        DirScan(const char *path, int bufsize = DEF_DIRSCAN_BUFSIZE);

        shrc open(const char *path, int bufsize = DEF_DIRSCAN_BUFSIZE);

        shrc next(DirEntry *entry);

        ~DirScan();
        shrc close();

        bool is_open();
        shrc rc();
        int operator==(shrc &rc);
        int operator!=(shrc &rc);
    };

Here, we describe each of the methods of DirScan:

bool DirScan::is_open();
This method indicates whether the scan is open or closed.

shrc DirScan::rc();
DirScan::rc returns the return code generated by the last operation on the scan object.

int DirScan::operator==(shrc rc);
int DirScan::operator!=(shrc rc);

These operators provide a convenient way to check the status of the scan. For example, applications can say: if(scan == RCOK) ... or if (scan != RCOK) ....

DirScan::DirScan()
This method is the default constructor for DirScan. It constructs a closed scan. A scan can be opened on the object by calling open, below.

DirScan::DirScan(const char *path, int bufsize);
This constructor attempts to construct an open scan object. The path argument should indicate a valid directory in the Shore filesystem, on which the current transaction has at least read permission. The bufsize argument indicates the size of the scan's buffer. This parameter defaults to DEF_DIRSCAN_BUFSIZE, which is large enough to hold at least one directory entry. When using this constructor, the application should check to make sure that the scan was successfully opened before attempting to use the scan. The is_open method (above) will return true if the scan was successful, false otherwise. Alternately, the rc method can be used for this purpose. It will return RCOK if the scan was successfully open. Any other return value indicates that a scan was not opened.

shrc DirScan::open(const char *path, int bufsize);
This method opens a closed scan object. As with the above constructor, path should indicate a valid directory on which the transaction has at least read permission, and bufsize indicates the size of the scan's buffer. Upon successful completion, RCOK is returned. Any other return value indicates an error condition.

shrc DirScan::next(DirEntry *entry);
The method returns the next directory entry in the scan. (See the above description of the DirScan type.) If the next entry in the scan was successfully retrieved, then RCOK is returned. If an attempt is made to advance the scan past the end of the scan (i.e., next is called after the last item in the scan has already been returned), the the return code will be OC_EndOfScan. Any other return code indicates an error condition.

shrc DirScan::close()
Closes the scan object. Closing a scan object releases any resources associated with the scan in both the server and client processes (such as the scan buffer). It also allows the scan object to be reused. Ordinarily, a scan object does not get closed implicitly. This means that applications must call this method to close a scan, even if the end of the scan has been reached or an error condition has been encountered. However, a scan will be closed implicitly when the DirScan object is destroyed (either via operator delete or when the DirScan object goes out of scope), or when the transaction in which the scan was opened terminates.

DirScan::~DirScan()
The DirScan destructor closes the scan object if it is open.

3 A Directory Scan Example

The following function prints the name and loid of each entry in the directory given by the pathname argument.


    int count(const char *pathname)
    {
        DirEntry entry;
        int count = 0;

        // Open a scan over the pool given by "pathname."
        DirScan scan(pathname);

        // Make sure the scan was successfully opened.
        if(scan != RCOK){
            cout << "Error scanning directory " << pathname << ": "
                 << rc << endl;
            return 0;
        }

        // Scan until end-of-scan or an error is encountered.
        for(count = 0; scan.next(&entry) == RCOK; ++count);

        cout << path << " has " << count << " objects." << endl;

        // Check for errors.
        if(scan.rc().err_num() != OC_EndOfScan){
            cout << "Error scanning directory " << pathname << ": "
                 << rc << endl;
            return 0;
        }

        // The destructor will close the scan object.

        return count;
    }


zwilling@caseus.cs.wisc.edu
Thu Nov 3 14:18:50 CST 1994