/*
 *              _ f a k e i n o
 *
 *  Get a suitable value for "inode". 
 *
 *  This routine was developed, because I didn't like the previously used ways
 *  of faking the inode value: using the file date (what about the result
 *  of fast wcopy type actions, which may leave lots of files with the same
 *  date.)
 *
 *  Also, using just this one routine ensures that the inode values returned
 *  by different types of function for the same file will indeed be the same.
 *
 *  My intention when writing this routine was that I would use the drive ID /
 *  file ID pair to make an inode. Unfotunately, SMS2 / QXL /SMSQ, don't
 *  seem to supply unique values here, so I cannot use this, but use the
 *  same algorithm as Eric Slagter (corrected for the bug, by rotating instead
 *  of shifting, thereby loosing information on long names).
 *
 *  Erling Jacobsen, Apr 1994
 *
 *  AMENDMENT HISTORY
 *  ~~~~~~~~~~~~~~~~~
 *  28 May 94         - Added to C68 distribution as standard feature.  The
 *                      _fstat() library routine now calls this one.
 *
 *  10 Aug 95         - Removed _super() and _user() calls as it appears that
 *                      the getcdb() routine need not be in supervisor mode
 *                      when it is called.   Suggested by Erling Jacobsen.
 */

#define __LIBRARY__

#include <qdos.h>
#include <sys/stat.h>
#include <channels.h>

/*
 *  Based on the routine by Eric Slagter, but rotates instead of
 *  shifting, to make all characters significant, not just the ones
 *  that are not shifted out of the 32 bit range.
 */
#define BITS_IN_INO ((int)(8*sizeof(ino_t))) /* not 100% portable, but almost */ 

static ino_t NameToIno(const struct QLSTR *qlstr)
{
    ino_t   res = -1;
    short   len = qlstr->qs_strlen;

    while(--len >= 0 )
    {
        res = ((res & 7) << (BITS_IN_INO-3)) +       /* wrap lowest 3 bits */
              ((unsigned int)res >> 3);              /* shift the rest     */

        res ^= qlstr->qs_str[len];
    }

    return res;
}

ino_t _fake_inode(chanid_t channel)
{
    struct fs_cdefb  *cdb;
    struct chan_defb *chdefb;

    chdefb = _getcdb(channel);
    cdb = (struct fs_cdefb *) chdefb;


    /*
     *  If not a file system file, return something which will
     *  still be unique, at least among all non file system files.
     *  I don't know if the inode value will ever be needed in such
     *  a case, but better safe than sorry!
     */
    if( (long)_isfscdb(chdefb) == 0L )
        return (ino_t) (0x80000000UL | (unsigned long)channel);

    return NameToIno( &cdb->fs_name );
}

