/***************************************************************************
 $RCSfile: ctfilesystem2.h,v $
                             -------------------
    cvs         : $Id: ctfilesystem2.h,v 1.5 2003/04/24 01:43:29 aquamaniac Exp $
    begin       : Fri Aug 09 2002
    copyright   : (C) 2002 by Martin Preuss
    email       : martin@libchipcard.de

 ***************************************************************************
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
 *   MA  02111-1307  USA                                                   *
 *                                                                         *
 ***************************************************************************/


#ifndef CTFILESYSTEM2_H
#define CTFILESYSTEM2_H

#ifdef CT_USE_ENCRYPTION
/* FIXME: This is needed for GCC 3.2, because unistd.h and openssl/des.h have
 * different declarations concerning the exceptions to be thrown
 * without this you can not compile libchipcard on RedHat 8 systems.
 */
# define PERL5
# include <openssl/des.h>
# undef PERL5
#endif


#define CTFILESYSTEM_VERSION_MAJOR 1
#define CTFILESYSTEM_VERSION_MINOR 0

/**
 * Size of a base block. All other sizes used by the file system are multiple
 * of this.
 */
#define CTFILESYSTEM_BASEBLOCKSIZE 32

/**
 * Maximum capacity this file system supports. Actually this has implications
 * to the size of the data cache.
 * The hard limit is 64KB, because the ISO commands for the chipcard do not
 * allow specifying an offset beyond 64KB.
 */
#define CTFILESYSTEM_MAXSIZE (64*1024)


#define CTFILESYSTEM_FAT_LENGTH   256


#include <chipcard/ctmemorycard.h>
#include <chipcard/ctdatacache.h>


/**
 * @page cardfspage Card File System 1.0
 * @section datorg Data Organisation On The Card
 * @subsection baseblocks Base Blocks
 * The memory of the card is divided into <i>base blocks</i> (size is
 * currently 32 bytes). This is the smallest element that my file system
 * operates on. The size of everything in this file system is a multiple of
 * those basic block's size.
 *
 * @subsection superblock Super Block
 * At the beginning of the memory an informational
 * table describing the file system itself can be found (@ref CTSuperBlock).
 *
 * @subsection fat Block Allocation Table
 * Directly behind this super block is the block allocation table. Others
 * would call it a <i>FAT</i> (file allocation table). The size of this FAT
 * is fixed to 256 bytes. Each entry of the FAT is one byte wide and it
 * corresponds to one <i>data block</i> (the size of a data block
 * depends on the capacity of the card, but it is a multiple of a basic
 * block's size). Each entry holds one of the following:
 * <ul>
 *  <li>number of the next block in this chain (see below, 0-253)</li>
 *  <li>special value to flag that the end of a chain is reached</li>
 *  <li>special value to flag that this block is free</li>
 *  <li>special value to flag that a block is reserved</li>
 * </ul>
 *
 * When allocating a data block the FAT is scanned for an entry flagging a
 * free block (see above). If one is found then it will be set with the
 * special value flagging that this block is the last block of a chain.
 * When the next block is to be allocated, then additionally the previous
 * block (which now is not at the end anymore) receives the number of the
 * following block. The number of the first block is stored in the file's
 * directory entry, thus creating a block chain.<br>
 * The older ones among you may recognize this scheme.
 * That's the way MSDOS managed floppies and hard discs with their old
 * FAT (before NTFS or FAT32 came ;-)<br>
 *
 * @subsection dirent Directory Entries
 * Each file and folder is represented by a special
 * table (@ref CTDirEntry). This entry holds information about the file or
 * folder. If a folder contains sub folders, then their entries are stored
 * within the data area of the parent directory.
 */


#ifndef DOXYGEN
/**
 * @author Martin Preuss<martin@libchipcard.de>
 */
class CHIPCARD_API CTBlockMedium: public CTMemoryCard {
public:
  CTBlockMedium(const CTCard &c);
  virtual ~CTBlockMedium();

  virtual CTError readBlocks(int bn, int n, string &bl);
  virtual CTError writeBlocks(int bn, int n, const string &bl);
  virtual CTError mountMedium();
  virtual CTError unmountMedium();
};
#endif



#ifndef DOXYGEN
/**
 * @author Martin Preuss<martin@libchipcard.de>
 */
class CHIPCARD_API CTCachedBlockMedium: public CTBlockMedium {
private:
  CTDataCache<CTFILESYSTEM_MAXSIZE,32> _cache;
public:
  CTCachedBlockMedium(const CTCard &c);
  virtual ~CTCachedBlockMedium();

  virtual CTError readBlocks(int bn, int n, string &bl);
  virtual CTError writeBlocks(int bn, int n, const string &bl);
  virtual int flush(int maxb=0x800000) throw (class CTError);
  virtual void purge();
  virtual CTError mountMedium();
  virtual CTError unmountMedium();
};
#endif


#ifndef DOXYGEN
/**
 * @author Martin Preuss<martin@libchipcard.de>
 *
 */
class CHIPCARD_API CTCryptedBlockMedium: public CTCachedBlockMedium {
private:
  des_cblock _desKey1;
  des_cblock _desKey2;
  bool _desKeyIsValid;

protected:
  CTError crypt(bool encrypt, const string &src, string &dest);

public:
  CTCryptedBlockMedium(const CTCard &c);
  virtual ~CTCryptedBlockMedium();

  virtual CTError readBlocks(int bn, int n, string &bl,
			     bool cr=false);
  virtual CTError writeBlocks(int bn, int n, const string &bl,
			      bool cr=false);
  virtual CTError setPassword(const string &pw);
  virtual void clearPassword();
};
#endif



/* __________________________________________________________________________
 * AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 *                               CTSuperBlock
 * YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
 */


#define CTFS_SUPERBLOCK_FLAG_CRYPTED  0x0001
#define CTFS_SUPERBLOCK_FLAG_READONLY 0x0002


/**
 * This class represents a super block and therefore describes the file system
 * on a card. It contains information such as the used block size, the
 * capacity of the card and so on.
 * @author Martin Preuss<martin@libchipcard.de>
 */
class CHIPCARD_API CTSuperBlock {
private:
    bool _changed;
    string _mediumName;
    int _blockSize;
    int _blocks;
    int _mediumSize;
    unsigned char _versionMajor;
    unsigned char _versionMinor;
    unsigned int _flags;
    int _reservedBlocks;
    int _firstDirBlock;
    string _userName;

    CTError _fromString(const string &s);

public:
    /**
     * @name Constructors and destructors
     */
    //@{
    CTSuperBlock();
    /**
     * @internal
     */
    CTSuperBlock(const string &block);

    /**
     * @internal
     */
    CTSuperBlock(unsigned int mediumSize);
    ~CTSuperBlock();
    //@}

    /**
     * @name General information about the medium
     */
    //@{
    /**
     * Returns the name you assigned to the card. To protect yourself
     * against acidental data losses you should keeps the names of your
     * card unique !
     */
    const string mediumName() const { return _mediumName;};

    /**
     * Returns the capacity of the card. This value does not represent the
     * capacity for data storage, since the file system occupies a part
     * of the memory for management purposes.
     */
    int mediumSize() { return _mediumSize;};

    /**
     * Returns the major version of the file system on the card.
     * The file system library will refuse to mount a medium whose major
     * version does not math that of the library.
     */
    unsigned char versionMajor() const { return _versionMajor;};

    /**
     * Returns the minor version of the file system on the card. It may
     * differ from that of the library.
     * @todo When the minor version of the ard is higher than that of the
     * library we should mount the medium readonly !
     */
    unsigned char versionMinor() const { return _versionMinor;};

    /**
     * Tells whether the data on the card is encrypted.
     */
    bool isCrypted() const { return _flags & CTFS_SUPERBLOCK_FLAG_CRYPTED;};

    /**
     * Tells whether the data on the card should be protected against
     * writing.
     * @todo I must implement this feature.
     */
    bool isReadOnly() const { return _flags & CTFS_SUPERBLOCK_FLAG_READONLY;};
    //@}

    /**
     * @name Structural information
     */
    //@{
    /**
     * Returns the size of a data block in bytes. You can use this and the
     * value of @ref blocks() to determine the for data storage usable
     * capacity of the card.
     */
    int blockSize() const { return _blockSize;};

    /**
     * Returns the number of data blocks on this card.
     * You can use this and the value of @ref blockSize() to determine the
     * for data storage usable capacity of the card.
     */
    int blocks() const { return _blocks;};
    //@}

    /**
     * @name Internal information
     *
     * These methods are not part of the API an may therefore change or even
     * disappear in future versions.
     */
    //@{
    /**
     * @internal
     */
    int reservedBlocks() const { return _reservedBlocks;};

    /**
     * @internal
     */
    int firstDirBlock() const { return _firstDirBlock;};

    /**
     * @internal
     */
    const string userName() const { return _userName;};

    /**
     * @internal
     */
    bool changed() const { return _changed;};
    //@}

    /**
     * @name Internal setters
     */
    //@{
    /**
     * @internal
     */
    void setMediumName(const string &n) { _mediumName=n; _changed=true;};

    /**
     * @internal
     */
    void setBlockSize(int n) { _blockSize=n; _changed=true;};

    /**
     * @internal
     */
    void setBlocks(int n) { _blocks=n; _changed=true;};

    /**
     * @internal
     */
    void setReservedBlocks(int i) { _reservedBlocks=i;};

    /**
     * @internal
     */
    void setMediumSize(int n) { _mediumSize=n; _changed=true;};

    /**
     * @internal
     */
    void setVersion(int mj, int mn) {
        _versionMajor=mj;
        _versionMinor=mn;
        _changed=true;};

    /**
     * @internal
     */
    void setIsCrypted(bool b) {
        if (b)
            _flags|=CTFS_SUPERBLOCK_FLAG_CRYPTED;
        else
            _flags&=~CTFS_SUPERBLOCK_FLAG_CRYPTED;
        _changed=true;};

    /**
     * @internal
     */
    void setIsReadOnly(bool b) {
        if (b)
            _flags|=CTFS_SUPERBLOCK_FLAG_READONLY;
        else
            _flags&=~CTFS_SUPERBLOCK_FLAG_READONLY;
        _changed=true;};

    /**
     * @internal
     */
    void setFirstDirBlock(int i) { _firstDirBlock=i; _changed=true;};

    /**
     * @internal
     */
    void setUserName(const string &n) { _userName=n; _changed=true;};

    /**
     * @internal
     */
    void setChanged(bool b) { _changed=b;};
    //@}

    /**
     * @name Internal conversion operations
     */
    //@{
    /**
     * @internal
     */
    string toString();

    /**
     * @internal
     */
    string dump();
    //@}
};





/* __________________________________________________________________________
 * AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 *                               CTBlockManager
 * YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
 */


#ifndef DOXYGEN
/**
 * @author Martin Preuss<martin@libchipcard.de>
 *
 */
class CHIPCARD_API CTBlockManager {
private:
    unsigned char _fat[CTFILESYSTEM_FAT_LENGTH];
    int _blocks;
    bool _changed;

public:
    CTBlockManager();
    CTBlockManager(int blocks, const string &fat="");
    ~CTBlockManager();

    bool changed() const { return _changed;};
    void setChanged(bool b) { _changed=b;};

    int allocateBlock(int bl=-1);
    void freeBlock(int bl);
    void freeChain(int bn);
    int blocks(int bl=-1);
    int freeBlocks();
    int blockAt(int first, int idx);

    int nextBlock(int bl);
    int previousBlock(int bl);
    int lastBlock(int bl);

    string toString();
};
#endif // DOXYGEN


/* __________________________________________________________________________
 * AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 *                               CTDataBlockMedium
 * YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
 */


#ifndef DOXYGEN
/**
 * This class operates on data blocks, whose size depends on the size
 * of the medium. Such a block consists of multiple base blocks.
 * @author Martin Preuss<martin@libchipcard.de>
 */
class CHIPCARD_API CTDataBlockMedium: public CTCryptedBlockMedium {
    friend class CTFileBase;

private:
    int _firstDataBlock;
    CTSuperBlock _superBlock;
    CTBlockManager _blockManager;
    bool _isMounted;

    CTError _createMedium(unsigned int mediumSize,
                          const string &mediumname,
                          const string &userName,
                          const string &passwd);
    CTError _readFAT();
    CTError _writeFAT();
    CTError _readSuperBlock();
    CTError _writeSuperBlock();

protected:
    CTDataBlockMedium(const CTCard &c);
public:
    virtual ~CTDataBlockMedium();

    virtual CTError readBlock(int bn, string &bl);
    virtual CTError writeBlock(int bn, const string &bl);
    virtual CTError allocateBlock(int &bn);
    virtual CTError freeBlock(int bn);
    virtual CTError freeChain(int bn);
    virtual CTError nextBlock(int &bn);
    const CTSuperBlock &superBlock() const { return _superBlock;};
    virtual int blocks(int bl=-1);
    virtual int freeBlocks();
    virtual int blockAt(int first, int idx);
    virtual int blockSize() const;
    virtual int firstDirBlock();
    virtual CTError mountMedium(const string &username="",
                                const string &passwd="");
    virtual CTError unmountMedium();
    virtual CTError createMedium(unsigned int mediumSize,
                                 const string &mediumname,
                                 const string &userName,
                                 const string &passwd);
    bool isReadOnly() const { return _superBlock.isReadOnly();};
    void setReadOnly(bool b) { _superBlock.setIsReadOnly(b);};
    virtual int flush(int maxb=0x800000) throw (class CTError);
    virtual void purge();
};
#endif // DOXYGEN





/* __________________________________________________________________________
 * AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 *                               CTDataFile
 * YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
 */


#ifndef DOXYGEN
/**
 * @author Martin Preuss<martin@libchipcard.de>
 *
 */
class CHIPCARD_API CTDataFile {
    friend class CTDirectoryBase;
    friend class CTFileBase;
private:
    string _buffer;
    int _block;
    int _pos;
    bool _dirty;
    bool _valid;
    int _allocatedSize;

    int _firstBlock;
    CTPointer<CTDataBlockMedium> _medium;

    CTError _readBlock();
    CTError _writeBlock();

protected:
    CTDataFile();
    CTDataFile(CTPointer<CTDataBlockMedium> medium,
               int firstBlock=0);
public:
    ~CTDataFile();

    CTError seek(int where);
    int position();
    unsigned char readChar();
    string readString(int len);
    CTError writeChar(unsigned char c);
    CTError writeString(const string &s);
    CTError flush();
    CTError truncate();
    int firstBlock() const { return _firstBlock;};

    int blocks();
    int allocatedSize();
    CTError appendBlock();

};
#endif // DOXYGEN





/* __________________________________________________________________________
 * AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 *                               CTDirEntry
 * YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
 */


/**
 * This class represents an entry of a folder and therefore describes
 * a file or directory. The only way to <br>get</b> an object of this class
 * which really describes a file is by calling @ref CTFile::statFile
 * @author Martin Preuss<martin@libchipcard.de>
 */
class CHIPCARD_API CTDirEntry {
private:
    bool _changed;
    string _name;
    unsigned int _attributes;
    unsigned int _size;
    int _firstBlock;
    int _parent;

    int _indexInParent;

    CTError _fromString(const string &s);

public:
    /**
     * Attributes of a file or folder.
     */
    enum Attributes {
        /**
         * Entry is in use
         */
        Attr_USED  =0x0001,
        /**
         * Reading the file/folder is allowed
         */
        Attr_READ  =0x0002,

        /**
         * Writing to the file/folder is allowed.
         */
        Attr_WRITE =0x0004,

        /**
         * Entry is a directory
         */
        Attr_DIR   =0x0008,

        /**
         * Entry is hidden (this attribure is currently unused)
         */
        Attr_HIDDEN=0x0010
    };

    /**
     * @name Constructors and destructors
     *
     * The only constructor you will be confronted with is that without
     * arguments, since you will rarely need create a valid direntry yourself.
     */
    //@{
    /**
     * This is the only constructor interesting for application developers.
     */
    CTDirEntry();

    /**
     * @internal
     */
    CTDirEntry(int parent,
               const string &name,
               unsigned int attribs=Attr_USED,
               unsigned int size=0,
               int firstblock=-1);

    /**
     * @internal
     */
    CTDirEntry(const string &s);

    /**
     * @internal
     */
    CTDirEntry(int parent, int indexInParent=-1);
    ~CTDirEntry();
    //@}
    /**
     * @name Retrieving information about this file or directory
     */

    //@{
    /**
     * Returns the name of this file or directory.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    const string &name() const { return _name;};

    /**
     * Returns the attributes of this file or directory (@ref Attributes)
     * @author Martin Preuss<martin@libchipcard.de>
     */
    unsigned int attributes() const { return _attributes;};

    /**
     * Size of this file. If this entry describes a directory then it's
     * is zero.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    int size() const { return _size;};
    //@}

    /**
     * @name Retrieving internal information
     *
     * The members returned here are internal and not part of the API,
     * so you should not expect them to be unchanged in future versions !
     */
    //@{
    /**
     * Was this entry changed since last read/write ?
     * @author Martin Preuss<martin@libchipcard.de>
     */
    bool changed() const { return _changed;};
    /**
     * Returns the number of the first block of this file.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    int firstBlock() const { return _firstBlock;};


    /**
     * This is the first block of the parent. This can be used to scan
     * the parent for entries. The parent is the folder where this entry
     * is contained.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    int parent() const { return _parent;};

    /**
     * This is the position within the parent folder where this entry is
     * contained. If -1 then this entry is a new one and has not been stored
     * yet.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    int indexInParent() const { return _indexInParent;};
    //@}

    /**
     * @name Internal setters
     */
    //@{
    /**
     * @internal
     */
    void setAttributes(unsigned int i) { _attributes=i; _changed=true;};

    /**
     * @internal
     */
    void setSize(unsigned int i) { _size=i; _changed=true;};
    /**
     * @internal
     */
    void setName(const string &s) { _name=s; _changed=true;};
    /**
     * @internal
     */
    void setFirstBlock(int i) { _firstBlock=i; _changed=true;};
    /**
     * @internal
     */
    void setParent(int i) { _parent=i; _changed=true;};
    /**
     * @internal
     */
    void setIndexInParent(int i) { _indexInParent=i;};
    /**
     * @internal
     */
    void setChanged(bool b) {  _changed=b;};
    //@}

    /**
     * @name Internal Conversion operations
     */
    //@{
    /**
     * @internal
     */
    string toString();
    /**
     * @internal
     */
    string dump();
    //@}

};





#ifndef DOXYGEN
/**
 *
 * @author Martin Preuss<martin@libchipcard.de>
 */
class CHIPCARD_API CTDirectoryBase: public CTDataFile {
private:
    CTDirEntry _entry;
    int _currEntry;

    CTError _readEntry(CTDirEntry &de, int idx);
    int _findFreeEntry();
    int _findOrAddFreeEntry();

public:
    CTDirectoryBase();
    CTDirectoryBase(CTPointer<CTDataBlockMedium> medium,
                    int firstBlock=0);
    ~CTDirectoryBase();

    CTError firstEntry(CTDirEntry &de);
    CTError nextEntry(CTDirEntry &de);
    CTDirEntry findEntry(const string &name);

    /**
     * Writes the given entry to the medium.
     * If the entries indexInParent() is valid then it will be used to
     * determine where to save this entry. Otherwise a new entry will
     * created on the medium and the indexInParent field will be updated.
     */
    CTError writeEntry(CTDirEntry &de);

};
#endif






#ifndef DOXYGEN
/**
 * @author Martin Preuss<martin@libchipcard.de>
 *
 */
class CHIPCARD_API CTFileBase {
    friend class CTFile;
    friend class CTDirectory;
private:
    CTPointer<CTDataBlockMedium> _medium;
    string _path;
    CTDirEntry _entry;
    bool _isOpen;
    CTDataFile _data;

    string _normalizeName(string n);
    CTError _createEntry(const string &n,
                         unsigned int attribs,
                         CTDirEntry &fileEntry);

protected:
    const CTDirEntry &dirEntry() const { return _entry;};
    CTDirEntry path2Entry(const string &path);
    CTError writeEntry(CTDirEntry &entry);

    CTFileBase();
public:
    CTFileBase(CTPointer<CTDataBlockMedium> medium,
          const string &path);
    virtual ~CTFileBase();

    bool isOpen() const { return _isOpen;};

    virtual CTError openFile();
    virtual CTError closeFile();
    virtual CTError createFile(unsigned int attribs=
                               CTDirEntry::Attr_USED |
                               CTDirEntry::Attr_READ |
                               CTDirEntry::Attr_WRITE);
    virtual CTError removeFile();
    virtual CTError statFile(CTDirEntry &ent);
    CTError renameFile(const string &n);

    CTError truncate();
    CTError seek(int where);
    int position();
    int size();
    unsigned char readChar();
    string readString(int len);
    CTError writeChar(unsigned char c);
    CTError writeString(const string &s);
    CTError flush();
};
#endif // DOXYGEN



/**
 * This class provides a file system on memory cards. If you want to access
 * files and/or directories on such a file system you need the classes
 * @ref CTFile and @ref CTDirectory.<br>
 * For information about the Card File System itself please go to
 * @ref cardfspage
 * @author Martin Preuss<martin@libchipcard.de>
 * @ingroup llcardfs
 * @short Provides a file system on memory cards
 */
class CHIPCARD_API CTCardFS: public CTDataBlockMedium {
private:
public:
  /**
   * @name Constructors/Destructors
   */
  //@{
  /**
   * This constructor is mainly used by derived classes to transform
   * a basic CTCard object to a more special one. This allows opening a
   * card as a CTCard object and then create e.g. a CTMemoryCard from
   * this one. The source card will be immediately closed. The only thing
   * you should do with it is to delete it. You should NOT use it any
   * longer !!
   * @param c reference to the CTCard object to be transformed
   * @author Martin Preuss<martin@libchipcard.de>
   */
  CTCardFS(const CTCard &c);
  virtual ~CTCardFS();
  //@}

  /**
   * @name Mounting and creating
   *
   * These methods allow mounting/unmounting and formatting of a memory
   * card. Mounting the card means to connect to the card thus making
   * it's content available. Upon mount all information necessary to
   * manage the medium is read from the card.
   */
  //@{
  /**
   * Connects the card and reads all information needed to manage the
   * file system on it (CTSuperBlock, the FAT).
   * If neither username nor passwd are given (or either one is empty)
   * then no encryption is assumed. However, the file system stores a flag
   * on the card (in the CTSuperBlock) to determine whether the data is
   * encrypted and refuses to mount when in the case of missing username
   * or password. This does not protect against reading raw data bytes
   * from the card but it prevents this class from accidentally
   * corrupting your data (in case of wrong or missing password).
   * @author Martin Preuss<martin@libchipcard.de>
   * @return error object (call isOk() on it to see if there was an error)
   * @param username name of the owner of the card. This name is given
   * upon creation of the file system on the card and cannot be altered.
   * @param passwd the password used for en-/decryption.
   */
  virtual CTError mountMedium(const string &username="",
			      const string &passwd="");

  /**
   * Unmounts the file system thus disconnecting the card physically.
   * Before disconnecting the cache is flushed.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return error object (call isOk() on it to see if there was an error)
   */
  virtual CTError unmountMedium() {
    return CTDataBlockMedium::unmountMedium();};

  /**
   * Format a memory card for use by the Card File System.
   * This method will create and write all data needed to manage a file
   * system on it. If username <b>and</b> password are given then all
   * data will be encrypted. If either of them is missing, then the
   * card will not be in crypto mode (not recommended)<br>
   * <b>Note:</b> This method does <b>not</b> leave the medium mounted !
   * @author Martin Preuss<martin@libchipcard.de>
   * @param mediumSize capacity of the card in bytes
   * @param mediumName assigns a name to the medium (up to 16 chars)
   * @param userName used for encryption, see introduction
   * @param passwd used for encryption
   */
  virtual CTError createMedium(unsigned int mediumSize,
			       const string &mediumName,
			       const string &userName,
			       const string &passwd);
  //@}

  /**
   * @name Information about the medium
   *
   * These method tell about the size of the medium, the number of
   * free blocks etc. They do only work if the medium is mounted.
   */
  //@{
  /**
   * All data of the file system is organized in data blocks. The size
   * of such a block depends on the capacity of your memory card.
   * @return number of blocks on this card
   * @author Martin Preuss<martin@libchipcard.de>
   */
  virtual int blocks() { return CTDataBlockMedium::blocks(-1);};

  /**
   * This method tells you how many unused blocks there are. This method
   * and @ref blockSize() will help you to determine the number of
   * free bytes on the card.
   * @return number of unused blocks
   * @author Martin Preuss<martin@libchipcard.de>
   */
  virtual int freeBlocks() { return CTDataBlockMedium::freeBlocks();};

  /**
   * This method returns the size of a data block. This size depends on
   * the capacity of your card. It is computed this way:
   *
   * <pre>
   *
   * int i;
   * int p;
   * int l;
   * int datasize;
   *
   * // calculate data size
   * // number of base blocks for superblock
   * p=CTFS_SUPERBLOCK_LENGTH/CTFILESYSTEM_BASEBLOCKSIZE;
   * if (CTFS_SUPERBLOCK_LENGTH % CTFILESYSTEM_BASEBLOCKSIZE)
   * p++;
   *
   * // calculate number of base blocks for FAT
   * l=CTFILESYSTEM_FAT_LENGTH/CTFILESYSTEM_BASEBLOCKSIZE;
   * if (CTFILESYSTEM_FAT_LENGTH % CTFILESYSTEM_BASEBLOCKSIZE)
   * l++;
   *
   * datasize=mediumsize-((p+l)*CTFILESYSTEM_BASEBLOCKSIZE);
   *
   * // calculate appropriate block size
   * _blockSize=datasize/253;
   * // size smaller than base block size ?
   * if (_blockSize<CTFILESYSTEM_BASEBLOCKSIZE)
   * _blockSize=CTFILESYSTEM_BASEBLOCKSIZE;
   * // is there a modulo ?
   * i=_blockSize % CTFILESYSTEM_BASEBLOCKSIZE;
   * if (i) {
   * // make block big enough to be divideable by base block size
   * _blockSize+=(CTFILESYSTEM_BASEBLOCKSIZE-i);
   * }
   *
   * // calculate block count (ignore modulo)
   * _blocks=datasize/_blockSize;
   *
   * </pre>
   * @author Martin Preuss<martin@libchipcard.de>
   * @return block size in bytes
   */
  virtual int blockSize() const { return CTDataBlockMedium::blockSize();};

  /**
   * The super block consists of the first blocks of the medium. It is
   * never encrypted (except the userName, which is encrypted).
   * This block holds some basic facts about the medium. Please refer
   * to @ref CTSuperBlock. The medium must already be mounted !
   * @author Martin Preuss<martin@libchipcard.de>
   * @return const reference to the superblock of this medium.
   */
  const CTSuperBlock &superBlock() const {
    return CTDataBlockMedium::superBlock();};

  /**
   * Currently this flag is ignored by libcardfs, but maybe later I will
   * implement a write protection.
   * @author Martin Preuss<martin@libchipcard.de>
   * @return true if the medium is write protected
   */
  bool isReadOnly() const { return CTDataBlockMedium::isReadOnly();};

  /**
   * Currently this flag is ignored by libcardfs, but maybe later I will
   * implement a write protection.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param b true if the medium shall be write protected
   */
  void setReadOnly(bool b) { CTDataBlockMedium::setReadOnly(b);};
  //@}

  /**
   * @name Cache Management
   *
   * These methods allow flushing and invalidating the data cache.
   * This cache holds all data blocks of the card that have been read or
   * written. The cache holds the data blocks as they are on the card,
   * so when using encryption the cache will only hold encrypted blocks.
   * This way the cache mechanism does not corrupt the security.
   */
  //@{
  /**
   * Flushes the cache. This means that all unwritten data will be
   * written to the card. This method should be called every once in a
   * while (as the CardFS daemon does) to protect your data against
   * getting lost (maybe due to a failure in one of the programs using
   * the Card File System).
   * @author Martin Preuss<martin@libchipcard.de>
   * @return number of blocks flushed (0 if none, -1 on error)
   * @param maxb number of blocks to flush. Flushing the whole cache
   * can take up to a minute or even longer, so if you just want to
   * flush some blocks of the cache (like the CardFS daemon) without
   * being busy and unresponsive for such a long time you can give the
   * number of blocks to write (8 is a fair value). However, when omitted
   * this number defaults to a value high enough to flush <b>all</b>
   * blocks.
   */
  virtual int flush(int maxb=0x800000) throw (class CTError) {
    return CTDataBlockMedium::flush(maxb);};

  /**
   * Invalidate the cache. You should call this prior to unmounting the
   * card if you don't want to committ changes to the card (Please
   * remember that @ref unmountMedium will flush the cache !)
   * @author Martin Preuss<martin@libchipcard.de>
   */
  virtual void purge() { CTDataBlockMedium::purge();};
  //@}
};



/**
 * @author Martin Preuss<martin@libchipcard.de>
 * @ingroup llcardfs
 */
class CHIPCARD_API CTFile: private CTFileBase {
    CTFileBase _fb;

public:
    /**
     * @name Constructors and destructors
     */
    //@{

    CTFile();

    /**
     * @author Martin Preuss<martin@libchipcard.de>
     * @param medium CTPointer to the medium this file belongs to (card)
     * @param path path of the file
     */
    CTFile(CTPointer<CTCardFS> medium,
           const string &path);
    ~CTFile();
    //@}

    /**
     * @name Opening, creating and closing operations
     *
     * Guess what these methods do...<br>
     * Some operations need the file to be open.
     */
    //@{
    /**
     * Opens a file. It must exist.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    CTError openFile() { return CTFileBase::openFile();};

    /**
     * Close a file that has been opened or created. There is no
     * nest counter, if the file is not open an error will be returned.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    CTError closeFile() { return CTFileBase::closeFile();};
    /**
     * Creates a file using the given attributes. If a file with that
     * name already exists an error will be returned.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    CTError createFile(unsigned int attribs=
                       CTDirEntry::Attr_USED |
                       CTDirEntry::Attr_READ |
                       CTDirEntry::Attr_WRITE){
        return CTFileBase::createFile(attribs|CTDirEntry::Attr_USED);
    };
    //@}

    /**
     * @name Renaming, removing, truncating or stating a file
     *
     * These operations perform with the file beeing either open or closed
     * (except removeFile, it needs the file to be closed).
     */
    //@{
    /**
     * Removes the file. If it does not exist anyway then an error will
     * be returned. The file must not be open..
     * @author Martin Preuss<martin@libchipcard.de>
     */
    CTError removeFile() { return CTFileBase::removeFile();};

    /**
     * Renames this file. This may move this file to a different folder.
     * The file may be open.
     * @author Martin Preuss<martin@libchipcard.de>
     * @param n new name
     */
    CTError renameFile(const string &n) { return CTFileBase::renameFile(n);};

    /**
     * Collects some information about the file. The file may be open or
     * closed.
     * @author Martin Preuss<martin@libchipcard.de>
     * @param ent reference to a CTDirEntry object to receive the info
     */
    CTError statFile(CTDirEntry &ent) { return CTFileBase::statFile(ent);};

    /**
     * Truncates file to zero.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    CTError truncateFile() { return CTFileBase::truncate();};;
    //@}

    /**
     * @name Seeking operations
     *
     * These methods deal with the current position within the file.
     * Obviously it needs to be open for these methods to perform.
     */
    //@{
    /**
     * Seeks to the given position. If the position is beyond the end of
     * this file no error is returned ! If a write follwos then the file
     * will grow to fit the size indicated by the file position. An
     * immediate read request however will fail
     * @author Martin Preuss<martin@libchipcard.de>
     * @param where position to seek
     */
    CTError seek(int where) { return CTFileBase::seek(where);};

    /**
     * Returns the current position of the file pointer.
     * @author Martin Preuss<martin@libchipcard.de>
     * @return current position in the file
     */
    int position() { return CTFileBase::position();};
    //@}

    /**
     * @name Reading and writing
     *
     * The following methods allow reading and writing data to/from a
     * file and advance the file pointer. The file needs to be open.
     */
    //@{
    /**
     * Read the next character out of the file. If the file pointers show
     * beyond the file's end an error will be thrown.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    unsigned char readChar() { return CTFileBase::readChar();};

    /**
     * Reads the next bytes up to the given length.
     * Calls @ref readChar().
     * @author Martin Preuss<martin@libchipcard.de>
     * @param len limit for the number of bytes to read
     */
    string readString(int len);

    /**
     * Writes a character to the current position in the file and
     * advances the file pointer. If the write position is beyond the
     * end of file an appropriate number of blocks will be allocated
     * for this file and assigned to it.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    CTError writeChar(unsigned char c) { return CTFileBase::writeChar(c);};

    /**
     * Writes a string of data to this file. Calls @ref writeChar().
     * @author Martin Preuss<martin@libchipcard.de>
     */
    CTError writeString(const string &s) {return CTFileBase::writeString(s);};

    /**
     * Flushes this file, which means all unwritten data will be written
     * to the medium. Well, it will rather be written to the cache of
     * the file system.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    CTError flush() { return CTFileBase::flush();};
    //@}
};





/**
 * This class represents a directory.
 * @author Martin Preuss<martin@libchipcard.de>
 * @ingroup llcardfs
 */
class CHIPCARD_API CTDirectory: private CTFileBase {

public:
    CTDirectory();
    CTDirectory(CTPointer<CTCardFS> medium,
                const string &path);
    ~CTDirectory();

    CTError openDirectory();
    CTError closeDirectory() { return CTFileBase::closeFile();};
    CTError createDirectory(unsigned int attribs=
                            CTDirEntry::Attr_USED |
                            CTDirEntry::Attr_READ |
                            CTDirEntry::Attr_WRITE){
        return CTFileBase::createFile(attribs|CTDirEntry::Attr_DIR);
    };

    CTError removeDirectory();
    CTError renameDirectory(const string &n) {
        return CTFileBase::renameFile(n);
    };

    CTError firstEntry(CTDirEntry &de);
    CTError nextEntry(CTDirEntry &de);
    CTError entry(CTDirEntry &de,int idx);

};



#endif



