#ifndef _NSREXT_ // -*-c++-*-
#define _NSREXT_

//----------------------------------------------------------------------
//  nsrExt.h
//   Classes for Physical and Logical Extents
//
//      Unpublished Confidential Information of Hewlett-Packard
//      Company. Do not disclose.  Copyright (c) Hewlett-Packard
//      Company 1995. All rights reserved
// 
// The contents of this software are proprietary and confidential to
// the Hewlett- Packard Company, and are limited in distribution to
// those with a direct need to know.  Individuals having access to
// this software are responsible for maintaining the confidentiality
// of the content and for keeping the software secure when not in use.
// Transfer to any party is strictly forbidden other than as expressly
// permitted in writing by Hewlett-Packard Company.  Unauthorized
// transfer to or possession by any unauthorized party may be a
// criminal offense.
//
//                  RESTRICTED RIGHTS LEGEND
//
//      Use,  duplication,  or disclosure by the U. S. Government is
//      subject to restrictions as set forth in subparagraph (c) (1)
//      (ii) in the Rights in Technical Data and Computer Software
//      clause in DFARS 252.227-7013 or any other successor clause.
//
//                      HEWLETT-PACKARD COMPANY
//                      3000 Hanover St.
//                      Palo Alto, CA  94304 U.S.A.
//
//      Rights for non-DOD U.S. Government Departments and Agencies
//      are as set forth in FAR 52.227-19 (c) (1,2) or any other
//      successor clause.
//  ENUMS:
//   ExtentType
//  CLASSES:
//   PhysExtent
//   PhysExtentList
//   PhysExtentListIter
//   LogExtent
//   LogExtentList
//   LogExtentListIter
//  
//----------------------------------------------------------------------
// $Source: /projects/HMS/nsr/udfCore/ss/nsrExt.h,v $
// $Revision: 1.74 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/06/21 23:36:44 $

//----------------------------------------------------------------------
// CLASS: PhysExtent     --DVM
//
//  Physical Extent - a contiguous set of sectors
//
// PhysExtents are the basic object for holding information about
// space on a piece of media. They are ALWAYS a multiple of the
// sectorSize in length. The principle ISO support is construction
// from and conversion to an ExtentDesc.
//
// PUBLIC METHODS:
// PhysExtent( PhysicalVolume *, UINT32 first, UINT32 number )
//    This constructs a PhysExtent on the supplied PhysicalVolume,
//    starting at the supplied sector address, and the supplied number
//    of sectors long.
// PhysExtent( PhysicalVolume *, ExtentDesc )
//    This constructs a PhysExtent on the supplied PhysicalVolume,
//    but getting its starting sector and number of sectors from the
//    supplied ExtentDesc.
// error()
//    This returns the error associated with the state of the
//    PhysExtent object, as well as its physical volume.
// toExtentDesc( ExtentDesc & ed )
//    This fills in the supplied ExtentDesc with the information
//    contained in the supplied PhysExtent.
// physVolume()
//    This returns a pointer the PhysicalVolume holding the
//    PhysExtent.
// startSector(),startSector(UINT32)
//    These return or modify the starting sector number of the
//    PhysExtent, respectively.
// numSectors(),numSectors(UINT32)
//    These return or modify the number of sectors in the
//    PhysExtent, respectively.
// numBytes()
//    This returns the length of the extent in bytes.
// sectorSize()
//    This returns the length of the sectors in the PhysExtent in
//    bytes.
// write()
//    This method writes the data in the argument ByteArrayRef to the 
//    PhysExtent on disk.
// writeWOE()
//    This method writes (using write-without-erase) the data in the argument
//    ByteArrayRef to the PhysExtent on disk.
// read()
//    This method reads the data into the argument ByteArrayRef from the 
//    PhysExtent on disk.
// erase()
//    This method erases the sectors specified by the PhysExtent.
//
// USAGE NOTES:
//  User notes go here.
// 
//----------------------------------------------------------------------
// COLLABORATORS:
//  PhysicalVolume
//
// PRIVATE METHODS:
//  none.
//
// IMPLEMENTATION NOTES:
//  Each PhysExtent contains a pointer to the PhysicalVolume to which
//  it belongs. This enables it to support the reading and writing,
//  since the PhysicalVolume contains a pointer to a device.
//
//----------------------------------------------------------------------

class PhysicalVolume;           // Forward reference... See nsrSSVol.h

class PhysExtent {

    PhysicalVolume *physVolumep_ ;     // pointer to volume holding extent.
    UINT32          startSector_ ;     // starting sector
    UINT32          numSectors_ ;     // length in sectors

public:

    Error error() const ;

    PhysExtent( PhysicalVolume * pvp, UINT32 first, UINT32 number ) ;
    // Default copy constructor is OK -- DVM

    void reinit( PhysicalVolume * pvp,
                 UINT32 first,
                 UINT32 number,
                 Error& err ) ;

    PhysicalVolume * physVolumep() const { return physVolumep_; }

    void removeStartSector() {
        if ( numSectors_ > 0 ) {
            startSector_++;
            numSectors_--;
        }
    }
    UINT32 startSector() const { return startSector_; }
    UINT32 numSectors() const { return numSectors_; }
    UINT16 sectorSize() const { return physVolumep_->sectorSize(); }
    UINT32 numBytes() const { return numSectors_ * sectorSize(); }

    INT32 write(const ByteArrayRef& arr, Error& err);
    INT32 writeWOE(const ByteArrayRef& arr,Error& err);
    INT32 read(const ByteArrayRef& arr, Error& err);
    INT32 erase(Error& err);
};

//----------------------------------------------------------------------
// CLASS: PhysExtentList     --DVM
//
//  List of Physical Extents
//
// This is a very simple container of PhysExtents. It allows basic
// access to its contents, and follows value-based semantics.
// 
// PUBLIC DATA MEMBERS:
//  type   member   <descr>
//  type   member   <descr>
//
// PUBLIC METHODS:
//
// PhysExtentList()
//    Default constructor makes an empty ExtentList.
// nullPointersError()
//    True if list has a null ptr within.
// error()
//    This returns the error state of the PhysExtentList.
// clear()
//    This empties the ExtentList, freeing the space allocated to all
//    contained extents.
// operator=()
//    This allows PhysExtentList assignment. It creates a deep copy.
// at()
//    This allows access to any PhysExtent in the PhysExtentList. Note
//    that the first PhysExtent is accessed via at(0)
// append(), concat()
//    A single PhysExtent may be appended via append(), and another
//    PhysExtentList may be appended via concat(). Note that
//    coalescing occurs here whenever possible.
// remove()
//    This removes the PhysExtent at the supplied index.
// numExtents()
//    This returns the number of PhysExtents in PhysExtentList.
// numSectors()
//    This returns the total length of the PhysExtents in sectors.
// numBytes()
//    This returns the total length of the PhysExtents in bytes. This
//    will always be a multiple of the sectorSize.
//
// USAGE NOTES:
//  Note that all physExtents in the list must be sector-multiple in
//  length.
// 
//----------------------------------------------------------------------
// COLLABORATORS:  
//  RWGSlist
//  PhysExtent
//
// PRIVATE METHODS:
//  copy(), free() - boilerplate.
//
// IMPLEMENTATION NOTES:
//  This container follows value semantics, even though it is built on
//  a collection following pointer semantics.
//
//----------------------------------------------------------------------

declare(RWGSlist, PhysExtent)

class PhysExtentList {

public:
    RWGSlist(PhysExtent) elist_;
private:
    Error allocError_;
    void copy_(const PhysExtentList &, Error & err);
    void free_() ;

public:

    PhysExtentList() : allocError_( error_None ) {} 
    PhysExtentList(const PhysExtentList &obj) {
        copy_(obj, allocError_);
    }
    ~PhysExtentList() { free_(); }

    Error error() const {return allocError_;}           
    Error nullPointersError() const;    

    void clear() { free_(); }

    PhysExtentList &operator=( const PhysExtentList &obj ) {
        copy_(obj, allocError_);
        return *this;
    }

    PhysExtent * at(UINT32 i, Error & err) ;
    const PhysExtent * at(UINT32 i, Error & err) const ;
    
    void append( const PhysExtent & pe, Error & err ) ;
    void concat( const PhysExtentList &pel, Error & err ) ;
    void remove( UINT32 i, Error & err );

    UINT32 numExtents() const { return elist_.entries(); }
    UINT32 numSectors() const ;
    UINT32 numBytes() const ;
};

//----------------------------------------------------------------------
// CLASS: PhysExtentListIter     --DVM
//
//  PhysExtentList Iterator, based on Rogue Wave SList Iterator
//
// PUBLIC METHODS:
// PhysExtentListIter()
//      Constructs an iterator.  Initially the current item is undefined.
//      You need to use operator()() or next() to get to the first item.
// operator()()
//      Advances the iterator to the next item and returns a pointer to it.  
//      Returns nil if at end of the list.
// next()
//      Advances the iterator to the next item.  Returns FALSE if there
//      is no next item (i.e., at End of List).
// atFirst()
//      Returns TRUE if iterator at start of list.  Else returns
//      FALSE. Does this mean at the first entry or just after list
//      construction????
// key()
//      Returns a ptr to the item at the current position.  Returns
//      nil if at end of list.  Returns nil if you use key() right
//      after the constructor.
// reset()
//      Resets the iterator to its initial state.  You need to use
//      operator()() or next() to get to the first item.
//
// USAGE NOTES:
//  Some of the boundary conditions are obscure, so the user should be
//  careful to read the above method descriptions very carefully.
// 
//----------------------------------------------------------------------
// COLLABORATORS:  
//  PhysExtentList
//  RWGSlistIterator
//
// PRIVATE METHODS:
//  none.
//
// IMPLEMENTATION NOTES:
//  Internal Notes go here (special cases, algorithm issues, etc.)
//
//----------------------------------------------------------------------


class PhysExtentListIter {

    RWGSlistIterator(PhysExtent) sli_;

public:
    PhysExtentListIter( PhysExtentList & list ) :
            sli_ (list.elist_) {}

    ~PhysExtentListIter() {}
    
    PhysExtent* operator()() { return sli_(); }
    void operator++(){ ++sli_; }
    Boolean next(){
        if ( sli_.atLast())
            return False;
        else {
            ++sli_;
            return True;
        }
    }
    
    Boolean atFirst() const {
        return (sli_.atFirst() ? True : False);
    }
    PhysExtent* key() {
        return sli_.key();
    }
    void reset() { sli_.reset(); }

};

//----------------------------------------------------------------------
// ENUM: ExtentType
//
//  These are the possible types of logical extents.
//
// DEFINITIONS:
//
//   Imaginary These LogExtents are unallocated and unrecorded. They
//             are simply placeholders when inside files, and have
//             only length, with no location associated with them.
//   Unerased  These LogExtents have been allocated, but have not yet
//             been recorded. Also, they may require erasure before
//             writing.
//   Erased    These LogExtents have been allocated, but have not yet
//             been recorded. Also, they do not require erasure
//             before writing.
//   Recorded  These LogExtents have been allocated, and are recorded.
//             These contain real file data.
//
// USES:
//  Since all logical space is represented via LogExtents, these types
//  define what type of space may be represented. 
//
// NOTES:
//
//----------------------------------------------------------------------
//  Note the relationship between these and the extent types allowed in
//  the actual standard -- These all map into those extent types,
//  except that these also support whether an extent is erased or not,
//  and do not support the concept of a continuation extent.
//----------------------------------------------------------------------
enum ExtentType {
    Imaginary = 0,
    Unerased  = 1,
    Erased    = 2,
    Recorded  = 3
};

//----------------------------------------------------------------------
// CLASS: LogExtent     --DVM
//
//  Logical Extent - A contiguous set of blocks inside a partition.
//
// PUBLIC METHODS:
// LogExtent()
//    The default constructor produces an empty LogExtent. If a length is
//    supplied, an imaginary LogExtent with the supplied length is
//    produced. A copy constructor is provided, so that LogExtents may be
//    used as arguments in function calls, etc.
// extentType()
//    This returns the type of the LogExtent.
// blockMultLen()
//    This returns the length of the LogExtent. It is ALWAYS a multiple
//    of LogicalBlockSize.
// maxInfoLen()
//    This returns the largest allowed number of bytes to fit into the
//    current extent.  NOTE that if the extent is imaginary, it will
//    allow the full 30 bits, while if it is not, but has a NULL
//    partition  pointer, it 
// infoLen()
//    This returns the number of bytes used in the LogExtent. It is
//    ALWAYS greater than or equal to (blockMultLen() -
//    LogicalBlockSize).
// markErased(), markRecorded()
//    These methods change the type of LogExtent. If an Unerased LogExtent
//    is erased, markErased() should be called. If an LogExtent is
//    recorded, markRecorded() should be called.
//
// USAGE NOTES:
//  These should SELDOM be created out of thin air. Rather, they
//  should be extracted from one of the following:
//  - SpaceResource
//  - Existing LogExtentLists
//  NOTE also that most users need not deal with LogExtents, but
//  should rather use LogExtentLists, which provide a higher level of
//  functionality.
// 
//----------------------------------------------------------------------
// COLLABORATORS:  
//  Partition
//  LogicalVolume
//
// PRIVATE METHODS:
//
// IMPLEMENTATION NOTES:
//  Perhaps LogExtents should NEVER be constructed from scratch (i.e.,
//  with arbitrary start and len values). For the preservation of
//  space, the file system will typically obtain this information
//  either from the SpaceResource objects (which break off pieces of
//  storage from the freedSpaceList or bitmap), or from the AD fields
//  in FEs, etc. Yes, even the locations to be searched for AVDPs are
//  defined by the standard. This means that PERHAPS the descr library
//  should make available static ExtentDescs which specify the
//  locations at which AVDPs might be found. The requirements for the
//  LogExtent are, of course nil.  However, the PhysExtent must merely
//  allow construction or conversion from an ExtentDesc. -DVM
//
// NOTE: The LogExtent is MODIFIED on the write from ERASED or
//   UNRECORDED to be RECORDED.  Further, an extent CANNOT BE READ
//   unless its type is RECORDED (as specified in the standard).
//   Thus, attempting to read into a ByteArray from an erased or
//   un-erased or unrecorded extent will be successful (no error),
//   but the ByteArray will merely be populated with ZEROS, and
//   the information on the SURFACE WILL NOT BE READ.
//----------------------------------------------------------------------

class Partition;                // forward reference ONLY
class LogicalVolume;            // forward reference ONLY

class LogExtent {

    ExtentType extentType_ ;
    Partition *partitionp_ ;    // pointer to partition holding extent.
    UINT32     startBlock_ ;    // starting block
    UINT32     infoLen_    ;    // length in bytes

public:

    // This should ONLY be used to TERMINATE a list.  This is
    //   an empty extent.  We should not grow it, it should always
    //   be empty.
    LogExtent(void) :
            partitionp_ ( NULL ),
            extentType_ ( Imaginary ),
            startBlock_ ( 0 ),
            infoLen_    ( 0 )
    {}
    
    LogExtent(Partition * pp, UINT32 len) :
            partitionp_ ( pp ),
            extentType_ ( Imaginary ),
            startBlock_ ( 0 ),
            infoLen_    ( len )
    {}

    LogExtent(Partition * pp, UINT32 st , UINT32 l)  :
            partitionp_ ( pp ),
            extentType_ ( Unerased ),
            startBlock_ ( st ),
            infoLen_    ( l )
    {}

    // Use DEFAULT copy constructor, so that partition pointer is
    // copied as well. -DVM

    void reinit(Partition *newpp,
                UINT32 start,
                UINT32 nBytes,
                Error& err) ;

    Partition * partitionp() const { return partitionp_; }
    void partitionp(Partition *newpp) { partitionp_ = newpp; }  
    LogicalVolume * logVolumep() const { return partitionp_->logVolumep(); }

    Error error() const ;
            
    ExtentType extentType() const { return extentType_; }
    ExtentType extentType(ExtentType newtype) {
        ExtentType oldtype = extentType_;
        extentType_ = newtype;
        return oldtype;
    }

    void markErased()   { extentType_ = Erased; }
    void markUnerased() { extentType_ = Unerased; }
    void markRecorded() { extentType_ = Recorded; }
    // Use of markImaginary() may cause space leak !!!
    void markImaginary() { extentType_ = Imaginary;}

    UINT32 startBlock(UINT32 newStartBlock) { return (startBlock_ = newStartBlock); }
    UINT32 startBlock(void) const { return startBlock_; }

    UINT32 blockSize(void) const {
        if(partitionp_)
           return partitionp_->blockSize();
        else
           //!!! HEY!  BAD FORM!  What should the block size be if
           //  we are simply an empty imaginary extent?  The user
           //  should NEVER call this!
           return 0;  // !!! KLUDGE!  What to do?
    }
    UINT32 numBlocks(void) const {
        UINT32 bs = partitionp_->blockSize();
        return ((infoLen_ + (bs - 1))/bs);
    }
    UINT32 blockMultLen(void) const {
        return partitionp_->blockSize() * numBlocks();
    }

    UINT32 infoLen(void) const { return infoLen_; }
    // NOTE: If this is an IMAGINARY extent with no partition pointer,
    //   then this operation will always FAIL!  (We cannot have an imaginary
    //   extent with a non-zero length with no partition pointer).
    UINT32 infoLen( const UINT32 il, Error & err ) ;

    UINT32 unusedLen(void) const
    {
        return blockMultLen() - infoLen_;
    }

    UINT32 maxInfoLen( void ) const {
        return (extentType_ == Imaginary) ? ExtLength::maxLength() :
            (partitionp_) ? partitionp_->maxExtLen() : 0;
    }

    Error validateLength(void) const
    {
        Error err(error_None);
        if ( infoLen() > maxInfoLen() )
            err = error_InfoLen_illegal;
        return err;
    }
    
    operator PhysExtent(void) ;

    Boolean operator!=(const LogExtent & other) const ;

    INT32 write(const ByteArrayRef& arr, Error& err);
    INT32 read(const ByteArrayRef& arr, Error& err);
    INT32 erase(Error& err);

    void print(UINT32 indent, const String & header = "") const ;

}; // class LogExtent

//----------------------------------------------------------------------
// CLASS: LogExtentList     --DVM
//
//  A list of Logical Extents.
//
//  This contains a series of LogExtents, where each
//      extent has an implied (logical) order in the list.  Thus, the
//      list will NOT re-order any extents placed in the list.  Each
//      extent added to the list must be from the same LogicalVolume
//      (and thus have the same blockSize()).  The list stores a
//      reference to its LogicalVolume (required on construction),
//      and confirms extents added are from this volume (or error on 
//      insert).
//
//  This class is the fundamental way of representing partition
//  space. It supports many methods, including
//  - representing lists inside of descriptors
//  - Reading, writing, erasing
//  - Breaking up and joining together
//
// PUBLIC METHODS:
// LogExtentList()
//    Default constructor makes an empty LogExtentList. If a length is
//    provided, it creates an LogExtentList with a single Imaginary
//    LogExtent with the associated infoLen.
// nullPointersError()
//    True if contains a null ptr.
// error()
//    This returns the error state of the LogExtentList.
// clear()
//    This empties the LogExtentList, freeing the space allocated to
//    all contained LogExtents.
// operator!=()
//    Not equals.
// operator=()
//    This allows LogExtentList assignment. It creates a deep copy
// numLogExtents()
//    This returns the number of LogExtents in LogExtentList.
// at()
//    This allows access to any LogExtent in the LogExtentList. Note
//    starts counting at 0.
// append(), concat()
//    A single LogExtent may be appended via append(), and another
//    LogExtentList may be appended via concat(). Note that coalescing
//    occurs here whenever possible.
// remove()
//    This removes the LogExtent at the supplied index.
// blockMultLen()
//    This returns the total length in bytes of the LogExtent, using
//    all the space in all the LogExtents. It is always a multiple of
//    the LogicalBlockSize.
// infoLen()
//    This returns or allows the setting of the number of valid bytes
//    in the LogExtentList. Note that this may differ from the
//    blockMultLen() only by less than a LogicalBlockSize, since this
//    difference is ONLY in the last LogExtent in the list.
// unusedLen()
//    This returns blockMultLen() - infoLen(). It is the residue in
//    the last LogExtent which is unused.
// recordedBlocks()
//    This returns the number of blocks in the LogExtentList which are
//    in Recorded LogExtents.
// headOf(), headXOf()
//    These return an LogExtentList which is identical to the head of
//    the current LogExtent, up through the offset supplied. head()
//    includes the Logical Block in which offset is located, while
//    headX() eXcludes it.
// tailOf(), tailXOf()
//    These return an LogExtentList which is identical to the tail of
//    the current LogExtent, starting at the offset supplied. tail()
//    includes the Logical Block in which offset is located, while
//    tailX() eXcludes it.
// read(), write()
//    These support basic IO operations to the extent list.
// appendFromADTable, toADTable         // Generic methods. 
// [to|from][Short|Long|Extended]ADT    // Specific methods. 
//    The calls to transform from and to an Alloc Desc Table.  
// print(), printVerbose()   
//    Prints out object.
//
// USAGE NOTES:
//  User notes go here.
// 
//----------------------------------------------------------------------
// COLLABORATORS:  
//  RWGSlist
//  LogExtent
//
// PRIVATE METHODS:
//  none.
//
// IMPLEMENTATION NOTES:
//  Internal Notes go here (special cases, algorithm issues, etc.)
//
//----------------------------------------------------------------------

declare(RWGSlist, LogExtent)

// !!! HEY!  We should verify that all extents added to a list
//  are from the same logical volume!!  The same block size!
// !!! HEY! We should impose checks that we will NEVER have a zero
//   length extent in a list!  That should never be allowed!  (It
//   would break code in "void LogExtentList::infoLen(UINT64)".
class LogExtentList {

public:
    RWGSlist(LogExtent) elist_;
private:
    // The following pointer is NEVER NULL!
    // We have it as a pointer, not a reference, so we can re-assign
    //   values through the assignment operator.
    LogicalVolume* logicalVolume_;

    Error allocError_;

    void copy_(const LogExtentList &, Error & err);
    void free_() ;

public:
    LogExtentList(LogicalVolume& logicalVolume) 
        : allocError_(error_None),
          logicalVolume_(&logicalVolume) {}
    LogExtentList(const LogExtentList &obj) {
        copy_(obj, allocError_);
    }
    ~LogExtentList() { free_(); }

    LogicalVolume& logicalVolume(void) const {
        return *logicalVolume_;
    }

    Error error() const { return allocError_;}
    Error nullPointersError() const;
    void clear() {
        allocError_ = error_None;
        free_();
    }

    LogExtentList &operator=( const LogExtentList &obj ) {
        copy_( obj, allocError_ ); 
        return *this;
    }

    // NOTE that the out of bounds error is no longer used RW
    // Exceptions will handle this error.

    LogExtent * at(UINT32 i, Error & err) ;
    const LogExtent * at(UINT32 i, Error & err) const ;

    // This function removes the LogExtent at the specified
    //   index and returns the extent to the caller.
    // NOTE: The caller must "delete" the extent!
    void removeExtent(LogExtent& logExtent, 
                            UINT32 index, 
                            Error& err) {
        LogExtent* temp = elist_.removeReference(at(index, err));
        if(temp && !err) {
            // If we could get this extent.
            logExtent = *temp;
            delete temp;
        }
    }

    // Return the largest extent length in this list.
    UINT64 maxExtentLen(void) const;

    // NOTE: Use "insertAt" to force a (new) LogExtent
    //   at the arbitrary location specified.  WARNING: This
    //   DOES NOT consider the appropriate logic disruption
    //   from forcing this LogExtent between two other LogExtents
    //   (that is the responsibility of the caller).  
    //   This is the ONLY insert function that will actually
    //   add an item to the list at any location, so that
    //   derived classes have a single point to modify adding
    //   behavior for append(), concat(), etc.
    // NOTE: This function is virtual because it is overridden
    //   by PackedLogExtentList.
    virtual void insertAt(const LogExtent& ext, UINT32 index, Error& err);

    void append( const LogExtent & ext, Error & err );
    void concat( const LogExtentList &el, Error & err ) ;
    void remove( UINT32 i, Error & err );
    void collapse( Error & err );

    UINT32 numLogExtents() const { return elist_.entries(); }

    static UINT64 calcBlockMultByteLen(UINT64 byteLen, UINT32 blockSize) {
        if (Trace::logAlgorithms()) {
            printf("Round %ld to block multiple of %ld\n", byteLen, blockSize);
        }
        UINT64 returnVal = byteLen;
        if(blockSize) {
            // If we have a blocksize.
            if(returnVal % blockSize) {
                // If this is not a perfect multiple of blockSize.
                returnVal = (UINT64(returnVal/blockSize) + 1) * blockSize;
                if (Trace::logAlgorithms()) {
                    printf("Rounded %ld to block multiple of %ld\n", byteLen, returnVal);
                }
            }
        } else {
            if (Trace::logAlgorithms()) {
                printf("HEY!  Blocksize is zero!\n");
            }
        }
        return returnVal;
    }
    UINT64 blockMultLen() const;

    UINT64 infoLen() const ;
    // This function will set the infoLen() for the LogExtentList,
    //   but the requested value should be within the range of the
    //   one block for the blockMultLen() for the entire list.  Thus,
    //   this function will merely set the new infoLen() for the
    //   last extent in the list, which will NOT set the length
    //   across a block boundary.
    void infoLen( UINT64 len, Error& err ); // only modifies last LogExtent

    UINT32 unusedLen() const;   // blockMultLen() - infoLen()
    UINT64 recordedBlocks(void) const;

    UINT32 numExtents() const { return elist_.entries(); }
    UINT32 logBlockNo( const UINT64 offset ) const;

    // NOTE: The "extract..." member functions DESTRUCTIVELY remove
    //   from the extent list!  For these operations, we accept an
    //   infolen (or byteLen) request, and the returned extent has
    //   EXACTLY the infoLen (byteLen) requested!
    // NOTE: A LogExtentList ALWAYS conserves space at the BLOCK
    //   level, but can't at the byte level! This is because a
    //   request for ONE byte at the head of the list will force
    //   the LogExtentList to REMOVE ONE BLOCK and set the infoLen()
    //   to one byte!  Blocks are conserved, but bytes are not.
    //   Of course, if all requests are block multiples, then bytes
    //   can also be conserved.
    // POLICY:  If the list has enough block multiples to honor the
    //   byteLen requested, the request will be satisified; further,
    //   the returned extent (or extent list) will be EXACTLY the
    //   byte length requested (we will shorten the infoLen from 
    //   the extent(s) we had to extract from our list).
    // NOTE: If the LogExtentList has a LAST EXTENT of FIVE BYTES,
    //   and the caller wants to extract the extent from the tail
    //   for 100 bytes, the call will succeed!  We will "grow"
    //   the last extent to 100 bytes, and remove that last block!
    //   We can do this because that whole block (512 or 1024 bytes)
    //   is set aside for that extent, and if it is only 5 bytes long,
    //   we KNOW there is plenty of un-used space there.  Of course,
    //   the user can call the list to get the length of the last
    //   extent and extract from tail exactly that length if the user
    //   is doing something else (like packing) into that other space.
    // NOTE: Because of this policy, ALL EXTENTS WITH AN INFOLEN OF
    //   NON-BLOCK MULTIPLE CAN ALWAYS BE GROWN TO THE INFOLEN OF
    //   THE BLOCK MULTIPLE!!  This means if you find an extent
    //   with one byte, and your block length is 512 bytes, you can
    //   ALWAYS and ARBITRARILY grow that extent up to 512 bytes!
    //   (You can always put more stuff in there).  This is because
    //   any extent with non-block multiples is wasting space.
    //   Further, NO TWO EXTENTS CAN MAP TO THE SAME BLOCK.  That
    //   is why we can safely grow an extent up to all the blocks
    //   it references.  --cbay, 4-12-96

    // NOTE:  All of the destructive calls will ROUND the request UP
    //   to the nearest BLOCK LENGTH because all LogExtents must
    //   begin on a block boundary.  They will extract that number
    //   of blocks.  Then, they will shorten the infoLen() back
    //   to the exact length of the request (if the user asked for
    //   one byte, the user gets an extent with an infoLen() of one
    //   byte, even though the block is actually wasting 511 bytes
    //   on a 512 byte blocksize.
    // Remove the first extent from the list.
    void takeFirstExtent(LogExtent& logExtent,
                         Error& err);
    // Remove the last extent from the list.
    void takeLastExtent(LogExtent& logExtent,
                        Error& err);
    // Cut "desiredLen" off of the LogExtent at this index (from the
    //   beginning of the extent), and leave the rest in the list.  
    //   Return an extent (the first parameter) with the cut-off 
    //   portion.
    void extractHeadPartOfLogExtent(LogExtent& logExtent, 
                                    UINT32 index, 
                                    UINT64 byteLen, 
                                    Error& err);
    void extractTailPartOfLogExtent(LogExtent& logExtent, 
                                    UINT32 index, 
                                    UINT64 byteLen, 
                                    Error& err);
    void extractLogExtentFromHead(LogExtent& logExtent, 
                                  UINT64 byteLen, 
                                  Error& err);
    void extractLogExtentFromTail(LogExtent& logExtent, 
                                  UINT64 byteLen, 
                                  Error& err);
    void extractLogExtentListFromHead(LogExtentList& list, 
                                      UINT64 desiredLen, 
                                      Error& err);
    void extractLogExtentListFromTail(LogExtentList& list, 
                                      UINT64 desiredLen, 
                                      Error& err);

    // The following operations are NON-DESTRUCTIVE in manipulating the list!
    void HeadOf(  const LogExtentList& list,
                  UINT64 offset,
                  Error& err ) ;
    void TailOf(  const LogExtentList& list,
                  UINT64 offset,
                  Error& err ) ;
    void HeadXOf( const LogExtentList& list,
                  UINT64 offset,
                  Error& err ) ;
    void TailXOf( const LogExtentList& list,
                  UINT64 offset,
                  Error& err ) ;

    INT32 read(const ByteArrayRef& arr,Error& err );
    INT32 write(const ByteArrayRef& arr,Error& err );

    void printVerbose(void) ;
    void print(const UINT32 indent, const String &header) const ;

    Boolean operator!=( const LogExtentList & other ) const; 
    
};

//----------------------------------------------------------------------
// CLASS: PackedLogExtentList     --CSB
//
//  A packed list of Logical Extents.  This is different from a
//  normal LogExtentList in that all append(), insertAt(), etc.
//  functions will coalesce the new extent with the existing
//  (neighboring) extents if possible.
//
// PUBLIC METHODS:
// PackedLogExtentList()
//    Default constructor makes an empty PackedLogExtentList. If a length is
//    provided, it creates an LogExtentList with a single Imaginary
//    LogExtent with the associated infoLen.
// 
//----------------------------------------------------------------------
// COLLABORATORS:  
//  LogExtentList (is a base class we derive from)
//
// PRIVATE METHODS:
//  none.
//
// IMPLEMENTATION NOTES:
//  The insertAt() function will coalesce the new extents with
//  the existing ne ghboring extents, if possible.  All append(), etc.
//  functions in the base class rely upon this insertAt() implementation
//  for their logic, so all extents added will be coalesced.
//----------------------------------------------------------------------
class PackedLogExtentList : public LogExtentList {
    
private:
    // These functions are static members because they do not need
    //   to rely on any data members.
    static Boolean canCoalesce_(const LogExtent& extent1, 
                                const LogExtent& extent2); 
    // Increase the size of the grow_extent to also include the
    //   appended_extent.
    static void doCoalesce_(LogExtent& growExtent, 
                            const LogExtent& appendedExtent, 
                            Error& err); 

public:
    PackedLogExtentList(LogicalVolume& logicalVolume)
        : LogExtentList(logicalVolume) {}
    PackedLogExtentList(const PackedLogExtentList &obj) 
        : LogExtentList(obj) {}

    // NOTE: Use "insertAt" to force a (new) LogExtent
    //   at the arbitrary location specified.  WARNING: This
    //   DOES NOT consider the appropriate logic disruption
    //   from forcing this LogExtent between two other LogExtents
    //   (that is the responsibility of the caller).  However,
    //   this is the ONLY insert function that will coalesce
    //   neighboring LogExtents together, so THIS SHOULD BE
    //   THE ONLY IMPLEMENTATION FUNCTION USED TO SUPPORT append(),
    //   concat(), etc.
    // NOTE: This function is virtual because it is overridden
    //   by PackedLogExtentList.
    virtual void insertAt(const LogExtent& ext, UINT32 index, Error& err);
};


//----------------------------------------------------------------------
// CLASS: LogExtentListIter     --DVM
//
//  Iterator for LogExtentList - based on RWSlistIterator
//
// PUBLIC METHODS:
// LogExtentListIter(LogExtentList)
//      Constructs an iterator.  Initially the current item is undefined.
//      You need to use operator()() or next() to get to the first item.
// operator()()
//      Advances the iterator to the next item and returns a pointer to it.  
//      Returns nil if at end of the list.
// next()
//      Advances the iterator to the next item.  Returns FALSE if there
//      is no next item (i.e., at End of List).
// atFirst()
//      Returns TRUE if iterator at start of list.  Else returns
//      FALSE. Does this mean at the first entry or just after list
//      construction????
// key()
//      Returns a ptr to the item at the current position.  Returns nil if at 
//      end of list.  Returns nil if you use key() right after 
//      the constructor.
// reset()
//      Resets the iterator to its initial state.  You need to use
//      operator()() or next() to get to the first item.
//
// USAGE NOTES:
//  Some of the boundary conditions are obscure, so the user should be
//  careful to read the above method descriptions very carefully.
// 
//----------------------------------------------------------------------
// COLLABORATORS:  
//  LogExtentList
//  RWGSlistIterator
//
// PRIVATE METHODS:
//
// IMPLEMENTATION NOTES:
//  Internal Notes go here (special cases, algorithm issues, etc.)
//
//----------------------------------------------------------------------

class LogExtentListIter {

    RWGSlistIterator(LogExtent) sli_;

public:
    LogExtentListIter( LogExtentList & list ) :
            sli_ (list.elist_) {}

    ~LogExtentListIter() {}
    
    LogExtent* operator()() { return sli_(); }
    void operator++(){ ++sli_; }
    Boolean next(){
        if ( sli_.atLast())
            return False;
        else {
            ++sli_;
            return True;
        }
    }
    
    Boolean atFirst() const {
        return (sli_.atFirst() ? True : False);
    }
    LogExtent* key() {
        return sli_.key();
    }
    void reset() { sli_.reset(); }

};

#endif  // _NSREXT_
