//-*-c++-*--------------------------------------------------------------
//  nsrAttr.cpp
//  This file implements the member functions for the Attributes class,
//    as well as some member functions for PackedTac and Permissions,
//    which are private member classes to the Attributes class.
//
//      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.
//
//----------------------------------------------------------------------
//
// $Source: /projects/HMS/nsr/udfCore/descr/nsrAttr.cpp,v $
// $Revision: 1.17 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/05/23 10:32:11 $
//

#include <nsrLib.h>

#if 0 // NOTE: We don't implement these here because the Mac
//   compiler (apparently) can't read these nested
//   data members.
// PackedTAC

//----------------------------------------------------------------------
// METHOD: PackedTAC::PackedTAC  --<CSB>
//      
// NOTES:
//  All bits are set by default to zero, or to whatever bit values are
//    passed in through the UINT16.
//----------------------------------------------------------------------
NSR::Attributes::PackedTAC::PackedTAC(UINT16 newTac)
{
    tac_ = newTac;
}

//----------------------------------------------------------------------
// METHOD: PackedTAC::~PackedTAC  --<CSB>
//----------------------------------------------------------------------
NSR::Attributes::PackedTAC::~PackedTAC(void)
{
}

//----------------------------------------------------------------------
// METHOD: Permissions::Permissions  --<CSB>
//      
// NOTES:
//  All bits are set by default to zero, or to whatever bit values are
//    passed in through the UINT16.
//----------------------------------------------------------------------
NSR::Attributes::Permissions::Permissions(UINT16 newPermissions)
{
    permissions_ = newPermissions;
}

//----------------------------------------------------------------------
// METHOD: Permissions::~Permissions  --<CSB>
//----------------------------------------------------------------------
NSR::Attributes::Permissions::~Permissions(void)
{
}
#endif  // End, put inline in header.

//----------------------------------------------------------------------
// METHOD: Attributes::Attributes  --CSB
//
// NOTES:
//  The constructor zero's out all values by default, and takes no
//    parameters.
//----------------------------------------------------------------------

NSR::Attributes::Attributes(void) 
        :
        uid_                           (0),
        gid_                           (0),
        fileCharacteristics_           (0),
        filePermissions_               (0),
        accessTime_                    (0),
        modificationTime_              (0),
        attributeTime_                 (0),
        linkCount_                       (0)
{
}

//----------------------------------------------------------------------
// METHOD: Attributes::~Attributes  --CSB
//----------------------------------------------------------------------

NSR::Attributes::~Attributes(void)
{
    // We manage no memory, we need to do nothing.
}

//----------------------------------------------------------------------
// METHOD: Attributes::toFileEntry  --CSB
//      
// Set the FileEntry passed in with our internal data values.
//
// ARGS:
//  FileEntry   IN/OUT  Set to new values according to our internal state.
//
// POST-CONDS: (E.g., changes to class data members)
//  FileEntry is modified to reflect the Attributes state.
//
// NOTE:
//  The Attributes class is aware of the FileEntry interface, but the
//    reverse is not true.
//----------------------------------------------------------------------
void
NSR::Attributes::toFileEntry(NSR::FileEntry& fileEntry)  
{
    // NOTE:  On EVERY WRITE, we set the values of the following bits
    //   to zero.  (We do not support any value for these bits other than
    //   zero at the present time.)
    sortedDirectoryBit(False);
    nonRelocatableBit(False);
    contiguousBit(False);
    transformedBit(False);
    multiVersionsBit(False);

    if(fileType() == file_ExtendedAttributes)
    { // !!! All attributes EXCEPT FileType and Times are ZERO for ExtendedAttributes!

        // Zero all the data members out, in case they have a value now!
        uid(0);
        fileEntry.uid  = uid();
        gid(0);
        fileEntry.gid  = gid();
      
        fileEntry.icbTag.fileType((UINT8) file_ExtendedAttributes);

        fileCharacteristics_.characteristics(0);
        fileEntry.icbTag.flags.miscCharacteristics = 0;
    
        // We can access the packed permissions all together.
        filePermissions_.setAllPermissions(0);
        fileEntry.permissions.all    = 0;
  
        linkCount(0);
        fileEntry.fileLinkCount       = linkCount();
  
        // NOTE:  These times are sent as-is (preserve times and FileType).
        fileEntry.accessTime          = accessTime();
        fileEntry.modifyTime          = modificationTime();
        fileEntry.attributeTime       = attributeTime();
  
        // DONE.  At this point, we successfully updated the fileEntry
        //   object.  
    }
    else
    { // We are not processing a file_ExtendedAttributes, so just set the
        //   items out as-is.

        fileEntry.uid                = uid();
        fileEntry.gid                = gid();
      
        // Now, set the file characteristics.
        // RECALL:  We only allow for File Characteristics flags from
        // the range of 3 - 12, for a total of 10 possible values (the
        // other values are meaningless in the Attributes struct).
        // Thus, we reserve the lower 12 bits for these values, with
        // the highest 4 bits set aside for the FileType.  (The lowest or 
        // right-most bit represents  the "File characteristics" bit 3, for 
        // "file is a directory" when set to one. 
  
        // First, set the file type.
        fileEntry.icbTag.fileType((UINT8) fileCharacteristics_.fileType());
        // Next, set the file characteristics.
        fileEntry.icbTag.flags.miscCharacteristics = fileCharacteristics_.characteristics();
    
        // RECALL: Permissions are set with 5 bits (DCRWX), for each owner, group, other.
        // We can access the packed permissions all together.
        fileEntry.permissions.all     = filePermissions_.getAllPermissions();
  
        fileEntry.fileLinkCount       = linkCount() ;
  
        fileEntry.accessTime          = accessTime();
        fileEntry.modifyTime          = modificationTime();
        fileEntry.attributeTime       = attributeTime();
  
        // DONE.  At this point, we successfully updated the fileEntry
        //   object.  
    }

    // At this point, we are done sending our data to the FileEntry object.
    //   We can read the values back and compare states, to confirm we wrote
    //   the data correctly.
  
#ifdef NSR_VERIFY
    Attributes verifyAttributes;
  
  // Read the attributes back.
    verifyAttributes.fromFileEntry(fileEntry);

    if(*this != verifyAttributes)
    { // If we did not read back the same attributes we wrote, we
        //   have a problem  (bad write).
        //...?
        printf("ERROR in Attributes::toFileEntry():  Read from Write failure.\n");
        RWCString cstr;
        printf("%s\n", appendAttributes(cstr = "attrib"));
        printf("%s\n", verifyAttributes.appendAttributes(cstr = "verifyAttributes"));
    }
#endif

    return;
}

//----------------------------------------------------------------------
// METHOD: Attributes::fromFileEntry  --CSB
//      
// Set ourselves with values from the FileEntry passed in.
//
// ARGS:
//  FileEntry   IN  Source for our new values.
//
// POST-CONDS:
//  All internal data members are modified to reflect the state of the
//    FileEntry object passed in.
// 
// NOTES:
//  This function extracts values from the FileEntry passed in, and modifies
//    the state of all internal Attribute data members to be consistent
//    with the FileEntry passed in.
//----------------------------------------------------------------------
void
NSR::Attributes::fromFileEntry(NSR::FileEntry& fileEntry)
{
    uid(fileEntry.uid);
    gid(fileEntry.gid);

    // Set the file type.
    fileCharacteristics_.fileType((FileType) fileEntry.icbTag.fileType());
    // Next, set the file characteristics.
    fileCharacteristics_.characteristics(fileEntry.icbTag.flags.miscCharacteristics);
  
    // RECALL: Permissions are set with 5 bits (DCRWX), for each owner, group, other.
    // We can access the packed permissions all together.
    filePermissions_.setAllPermissions((UINT16)fileEntry.permissions.all);

    // NOTE:  We subtract the one link that we automatically have for being
    //   a file in the NSR file system.
    linkCount(fileEntry.fileLinkCount);
  
    accessTime(fileEntry.accessTime);
    modificationTime(fileEntry.modifyTime);
    attributeTime(fileEntry.attributeTime);

    return;
}

//----------------------------------------------------------------------
// METHOD: Attributes::unixMode  --CSB
//      
// Set our Attributes to the values specified by the unix-packed
//   mode passed in.
//
// ARGS:
//  UINT16   IN/OUT  Each significant bit is defined in "/usr/include/sys/stat.h"
//
// NOTES:
//  This function will modify any internal state of the Attributes object
//    to synchronize with the unix mode passed in.
//----------------------------------------------------------------------
void
NSR::Attributes::unixMode(UINT16 newMode)
{
    // NOTE:  The following masks we use (like S_IRUSR, etc) come from
    //   the standard UNIX header "stat.h" (in "usr/include/sys").

  // NOTE:  If performance in this code is too slow, we can re-write
  //   it do by-pass the interface to our bits and set 3 bits at a time,
  //   instead of one (RWX at a time).

  // Set our internal permissions based on the unix-packed mode passed in.
  // NOTE:  This code ASSUMES that the bit positions for UNIX are RWX (they are).
  // RECALL:  The "Execute" bit is the right-most bit for each set of three.

#ifdef ATTR_TEST_DBUG
    {
        RWCString cstr;
        printf("%s\n", appendAttributes(cstr = "attrib"));
        printf("%s\n", verifyAttributes.appendAttributes(cstr = "verifyAttributes"));
    }

    UINT16 set3;
    set3 = ((newMode >> UnixModeUsrExecuteBitPosition) & RightThreeBitsMask);
  
    filePermissions_.usrRWXBits(set3);
#else

    filePermissions_.usrRWXBits(
        (newMode >> UnixModeUsrExecuteBitPosition) & RightThreeBitsMask);
#endif
    filePermissions_.grpRWXBits(
        (newMode >> UnixModeGrpExecuteBitPosition) & RightThreeBitsMask);
    filePermissions_.othRWXBits(
        (newMode >> UnixModeOthExecuteBitPosition) & RightThreeBitsMask);

    // NOTE:  The following bits are stored internally in fileCharacteristics_,
    //   NOT filePermissions_ like the 9 bits above (we store 15 bits for
    //   permissions, but UNIX does not recognize Chattr or Delete.
    stickyBit( (newMode & UnixModeStickyBitMask) ? True : False);
    setUidBit( (newMode & UnixModeSetUidBitMask) ? True : False);
    setGidBit( (newMode & UnixModeSetGidBitMask) ? True : False);
  
    // HUH?  Should we be setting other bits?
    // Right now, we are only setting the BOTTOM 12 BITS, not the top 4
    //   (the top four are always zero).  --CSB  9-13-95.
}

//----------------------------------------------------------------------
// METHOD: Attributes::unixMode  --CSB
//      
// Return a unix-packed mode value that represents the attributes
//   stored in our Attributes class.
//
// RETURNS:
//  Returns a UINT16 in the format of the Unix Mode type.
// 
// NOTES:
//  The Attributes class is not modified.
//----------------------------------------------------------------------
NSR::UINT16
NSR::Attributes::unixMode(void) const
{
    // NOTE:  The following masks we use (like S_IRUSR, etc) come from
    //   the standard UNIX header "stat.h" (in "usr/include/sys").

  // NOTE:  If performance in this code is too slow, we can re-write
  //   it do by-pass the interface to our bits and set 3 bits at a time,
  //   instead of one (RWX at a time).

    UINT16 mode;  // The mode we are populating.

    // Set the mode permissions based on our internal bits.
    // NOTE:  This code ASSUMES that the bit positions for UNIX are RWX (they are).
    // RECALL:  The "Execute" bit is the right-most bit for each set of three.
    mode  = filePermissions_.usrRWXBits() << UnixModeUsrExecuteBitPosition;
    mode |= filePermissions_.grpRWXBits() << UnixModeGrpExecuteBitPosition;
    mode |= filePermissions_.othRWXBits() << UnixModeOthExecuteBitPosition;
#ifdef ATTR_TEST_DBUG
    {
        RWCString cstr;
        printf("%s\n", appendAttributes(cstr = "attrib"));
    }
#endif

    // NOTE:  The following bits are stored internally in fileCharacteristics_,
    //   NOT filePermissions_ like the 9 bits above (we store 15 bits for
    //   permissions, but UNIX does not recognize Chattr or Delete.
    if( stickyBit() ) mode |= (0x0001 << UnixModeStickyBitPosition);
    if( setUidBit() ) mode |= (0x0001 << UnixModeSetUidBitPosition);
    if( setGidBit() ) mode |= (0x0001 << UnixModeSetGidBitPosition);

    // HUH?  Should we be setting other bits?
    // Right now, we are only setting the BOTTOM 12 BITS, not the top 4
    //   (the top four are always zero).  --CSB  9-13-95.

    return mode;
}

//----------------------------------------------------------------------
// METHOD: Attributes::operator==  --CSB
// Compare ourselves to another instance of the Attributes class, and
//   return True if we have the same state.
//----------------------------------------------------------------------
NSR::Boolean
NSR::Attributes::operator==(const NSR::Attributes& otherAttributes) const
{
    // Compare the elements of two Attributes classes, and confirm
    //   that they have the same values.

#if 1  // We want to always process this way.
    return 
        (
            (uid_                 == otherAttributes.uid_)                 &&
            (gid_                 == otherAttributes.gid_)                 &&
            ((fileCharacteristics_ == otherAttributes.fileCharacteristics_)==True) &&
            ((filePermissions_     == otherAttributes.filePermissions_)==True)     &&
            (accessTime_          == otherAttributes.accessTime_)          &&
            (modificationTime_    == otherAttributes.modificationTime_)    &&
            (attributeTime_       == otherAttributes.attributeTime_)       &&
            (linkCount_           == otherAttributes.linkCount_)
            ) ? True : False;
#else  // Was for debugging, maybe pull this out?
    UINT16 diffs = 0;

    diffs +=  (uid_                 == otherAttributes.uid_) == True                 ;
    diffs +=  (gid_                 == otherAttributes.gid_) == True                 ;
    diffs +=  ((fileCharacteristics_ == otherAttributes.fileCharacteristics_)==True) ;
    diffs +=  ((filePermissions_     == otherAttributes.filePermissions_)==True)     ;
    diffs +=  (accessTime_          == otherAttributes.accessTime_)  == True         ;
    diffs +=  (modificationTime_    == otherAttributes.modificationTime_)  == True   ;
    diffs +=  (attributeTime_       == otherAttributes.attributeTime_)   == True     ;
    diffs +=  (linkCount_           == otherAttributes.linkCount_) == True;

    if(diffs != 8) 
    {
        printf("in Attributes::operator==() diffs is %hu\n", diffs);
        RWCString cstr;
        printf("%s\n", appendAttributes(cstr = "attrib"));
        printf("%s\n", otherAttributes.appendAttributes(cstr = "otherAttributes"));

        // If we had seven "true" tests, we are ok.
        return True;
    }
    return False;
#endif
}

//----------------------------------------------------------------------
// METHOD: Attributes::<methodName>  --CSB
// Compare ourselves to another instance of the Attributes class, and
//   return True if we do not have the same state.
//----------------------------------------------------------------------
NSR::Boolean
NSR::Attributes::operator!=(const NSR::Attributes& otherAttributes) const
{
    // Pass the buck to the other comparison, but reverse the answers.
    return ((operator==(otherAttributes)) ==True) ? False : True;
}

NSR::CONST_CHAR_PTR
NSR::Attributes::appendOtherInfo(RWCString& cstr) const
{
    char tempFormatString[512];
    sprintf (tempFormatString, "uid 0x%lx gid 0x%lx times 0x%lx 0x%lx 0x%lx links %ld",
             (UINT32)uid(),
             (UINT32)gid(),
             (UINT32)accessTime(),
             (UINT32)modificationTime(),
             (UINT32)attributeTime(),
             (UINT32)linkCount());

    cstr += tempFormatString;

    return (CONST_CHAR_PTR) cstr;
}

