/*
 * nasd_edrfs_dir.h
 *
 * Directory access routines for NASD EDRFS.
 *
 * Authors: Nat Lanza, Ted Wong
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */

#ifndef _NASD__NASD_EDRFS_DIR_H_
#define _NASD__NASD_EDRFS_DIR_H_

#include <nasd/nasd_types.h>
#include <nasd/nasd_edrfs_types.h>

#define NASD_EDRFS_DIRPAGE_NUM_SLOTS 127

/*
 * Directory information is here for client side directory parsing
 */

#define NASD_EDRFS_DIRPAGE_SIZE      8192
#define NASD_EDRFS_DIRPAGE_SIZE_BITS   13
#define NASD_EDRFS_DIRSLOT_SIZE_BITS    6

struct nasd_edrfs_dirpage_s {
  nasd_edrfs_dirheader_t  header;
  nasd_edrfs_dirdata_t    data_slots[127];
};

typedef struct nasd_edrfs_dirpage_s nasd_edrfs_dirpage_t;

/*
 * flags:
 * 
 * 0000000000111111111122222222223333333333444444444455555555556666
 * 0123456789012345678901234567890123456789012345678901234567890123
 * |__||__||______||______|
 *  |   |     |       |
 *  |   |     |       |
 *  |   |     |        \__ length of this name segment [ 8] (15-23)
 *  |   |      \__________ number of slots             [ 8] (08-15)
 *  |    \________________ extra type                  [ 4] (04-07)
 *   \____________________ type                        [ 4] (00-03)
 *
 * secret messages encoded in the type:
 *  * first bit is validity -- 0 is an invalid entry.
 *  * second bit is "is this a normal filetype?".
 *
 */  

#define NASD_EDRFS_DIRD_TYPE_BOGUS     0x0   /* 0000 */
#define NASD_EDRFS_DIRD_TYPE_EXNAM     0x8   /* 1000 */
#define NASD_EDRFS_DIRD_TYPE_DATA      0x9   /* 1001 */
#define NASD_EDRFS_DIRD_TYPE_LINK      0xa   /* 1010 */
#define NASD_EDRFS_DIRD_TYPE_DIR       0xb   /* 1011 */
#define NASD_EDRFS_DIRD_TYPE_CHR       0xc   /* 1100 */
#define NASD_EDRFS_DIRD_TYPE_BLK       0xd   /* 1101 */
#define NASD_EDRFS_DIRD_TYPE_FIFO      0xe   /* 1110 */
#define NASD_EDRFS_DIRD_TYPE_SOCK      0xf   /* 1111 */

#define NASD_EDRFS_DIRD_EXTYPE_UNUSED  0x0    /* 0000 */

#define NASD_EDRFS_DIRD_TYPEMASK       0x00000f
#define NASD_EDRFS_DIRD_EXTYPEMASK     0x0000f0
#define NASD_EDRFS_DIRD_EXLENMASK      0x00ff00
#define NASD_EDRFS_DIRD_SEGLENMASK     0xff0000

#define NASD_EDRFS_DIRD_TYPESHIFT       0
#define NASD_EDRFS_DIRD_EXTYPESHIFT     4
#define NASD_EDRFS_DIRD_EXLENSHIFT      8
#define NASD_EDRFS_DIRD_SEGLENSHIFT    16

#define NASD_EDRFS_DIRD_FLAGS_TYPEOF(_f_) \
         ((int)(((_f_)&NASD_EDRFS_DIRD_TYPEMASK  )>>NASD_EDRFS_DIRD_TYPESHIFT  ))
#define NASD_EDRFS_DIRD_FLAGS_EXTYPEOF(_f_) \
         ((int)(((_f_)&NASD_EDRFS_DIRD_EXTYPEMASK)>>NASD_EDRFS_DIRD_EXTYPESHIFT))
#define NASD_EDRFS_DIRD_FLAGS_EXLEN(_f_) \
         ((int)(((_f_)&NASD_EDRFS_DIRD_EXLENMASK )>>NASD_EDRFS_DIRD_EXLENSHIFT ))
#define NASD_EDRFS_DIRD_FLAGS_SEGLEN(_f_) \
         ((int)(((_f_)&NASD_EDRFS_DIRD_SEGLENMASK)>>NASD_EDRFS_DIRD_SEGLENSHIFT ))

#define NASD_EDRFS_DIRD_FLAGS_SET_TYPE(_f_, _t_) \
         ((_f_)|=(((_t_)<<NASD_EDRFS_DIRD_TYPESHIFT  )&NASD_EDRFS_DIRD_TYPEMASK  ))
#define NASD_EDRFS_DIRD_FLAGS_SET_EXTYPE(_f_, _t_) \
         ((_f_)|=(((_t_)<<NASD_EDRFS_DIRD_EXTYPESHIFT)&NASD_EDRFS_DIRD_EXTYPEMASK))
#define NASD_EDRFS_DIRD_FLAGS_SET_EXLEN(_f_, _t_) \
         ((_f_)|=(((_t_)<<NASD_EDRFS_DIRD_EXLENSHIFT )&NASD_EDRFS_DIRD_EXLENMASK ))
#define NASD_EDRFS_DIRD_FLAGS_SET_SEGLEN(_f_, _t_) \
         ((_f_)|=(((_t_)<<NASD_EDRFS_DIRD_SEGLENSHIFT)&NASD_EDRFS_DIRD_SEGLENMASK))

#define NASD_EDRFS_DIRD_TYPEOF(_d_)   NASD_EDRFS_DIRD_FLAGS_TYPEOF((_d_)->flags)
#define NASD_EDRFS_DIRD_EXTYPEOF(_d_) NASD_EDRFS_DIRD_FLAGS_EXTYPEOF((_d_)->flags)
#define NASD_EDRFS_DIRD_EXLEN(_d_)    NASD_EDRFS_DIRD_FLAGS_EXLEN((_d_)->flags)
#define NASD_EDRFS_DIRD_SEGLEN(_d_)   NASD_EDRFS_DIRD_FLAGS_SEGLEN((_d_)->flags)

#define NASD_EDRFS_DIRD_IS_BOGUS(_d_) \
         (NASD_EDRFS_DIRD_FLAGS_TYPEOF((_d_)->flags)==NASD_EDRFS_DIRD_TYPE_BOGUS)
#define NASD_EDRFS_DIRD_IS_EXNAM(_d_) \
         (NASD_EDRFS_DIRD_FLAGS_TYPEOF((_d_)->flags)==NASD_EDRFS_DIRD_TYPE_EXNAM)
#define NASD_EDRFS_DIRD_IS_DATA(_d_) \
         (NASD_EDRFS_DIRD_FLAGS_TYPEOF((_d_)->flags)==NASD_EDRFS_DIRD_TYPE_DATA )
#define NASD_EDRFS_DIRD_IS_LINK(_d_) \
         (NASD_EDRFS_DIRD_FLAGS_TYPEOF((_d_)->flags)==NASD_EDRFS_DIRD_TYPE_LINK )
#define NASD_EDRFS_DIRD_IS_DIR(_d_) \
         (NASD_EDRFS_DIRD_FLAGS_TYPEOF((_d_)->flags)==NASD_EDRFS_DIRD_TYPE_DIR  )
#define NASD_EDRFS_DIRD_IS_CHR(_d_) \
         (NASD_EDRFS_DIRD_FLAGS_TYPEOF((_d_)->flags)==NASD_EDRFS_DIRD_TYPE_CHR  )
#define NASD_EDRFS_DIRD_IS_BLK(_d_) \
         (NASD_EDRFS_DIRD_FLAGS_TYPEOF((_d_)->flags)==NASD_EDRFS_DIRD_TYPE_BLK  )
#define NASD_EDRFS_DIRD_IS_FIFO(_d_) \
         (NASD_EDRFS_DIRD_FLAGS_TYPEOF((_d_)->flags)==NASD_EDRFS_DIRD_TYPE_FIFO )
#define NASD_EDRFS_DIRD_IS_SOCK(_d_) \
         (NASD_EDRFS_DIRD_FLAGS_TYPEOF((_d_)->flags)==NASD_EDRFS_DIRD_TYPE_SOCK )

#define NASD_EDRFS_DIRD_SET_TYPE(_d_, _n_) \
         (NASD_EDRFS_DIRD_FLAGS_SET_TYPE(((_d_)->flags), (_n_)))
#define NASD_EDRFS_DIRD_SET_EXTYPE(_d_, _n_) \
         (NASD_EDRFS_DIRD_FLAGS_SET_EXTYPE(((_d_)->flags), (_n_)))
#define NASD_EDRFS_DIRD_SET_EXLEN(_d_, _n_) \
         (NASD_EDRFS_DIRD_FLAGS_SET_EXLEN(((_d_)->flags), (_n_)))
#define NASD_EDRFS_DIRD_SET_SEGLEN(_d_, _n_) \
         (NASD_EDRFS_DIRD_FLAGS_SET_SEGLEN(((_d_)->flags), (_n_)))

/* utility functions */

#define NASD_EDRFS_DIRMAP_TEST_SLOT(_u_, _s_) \
        ( _u_[(_s_) >> 3]  &  (1 << ((_s_) % 8)) )

#define NASD_EDRFS_DIRMAP_SET_SLOT(_u_, _s_) \
        ( _u_[(_s_) >> 3] |=  (1 << ((_s_) % 8)) )

#define NASD_EDRFS_DIRMAP_CLEAR_SLOT(_u_, _s_) \
        ( _u_[(_s_) >> 3] &= ~(1 << ((_s_) % 8)) )

/* extract a name for easier comparison */
void nasd_edrfs_dir_extract_name(nasd_edrfs_dirpage_t  *page,
				 int                    slot,
				 char                  *name);
/* how many slots will a name take up? */
int nasd_edrfs_dir_name_len(char *name);

/* parse a raw disk block into a nasd_edrfs_dirpage_t struct */
void nasd_edrfs_dir_parse_page(void                  *raw_page,
			       nasd_edrfs_dirpage_t  *parsed_page);

/* parse a raw disk block into a nasd_edrfs_dirpage_t struct */
void nasd_edrfs_dir_parse_page_parts(void                  *raw_page1,
				     void                  *raw_page2,
				     nasd_edrfs_dirpage_t  *parsed_page);

void nasd_edrfs_dir_parse_page_inplace(nasd_edrfs_dirpage_t *page);

/* marshall a nasd_edrfs_dirpage_t struct into a raw disk block ready to
   be written out */
void nasd_edrfs_dir_marshall_page(nasd_edrfs_dirpage_t  *parsed_page,
				  void                  *raw_page);

/* look up an entry by name and return its index in the page.
   returns -1 if the entry isn't found. */
int nasd_edrfs_dir_lookup_entry(nasd_edrfs_dirpage_t  *page,
				char                  *name);

/* returns the index of the next valid entry in a dirpage. uses
   'marker' to keep track of where it is. returns -1 when there are
   no more valid entries in a page. */
int nasd_edrfs_dir_readdir(nasd_edrfs_dirpage_t  *page,
			   int                   *marker);

/* convert the specified directory slot to a dirent structure.
   fails if the slot is empty. */
nasd_status_t nasd_edrfs_dir_slot_to_dirent(nasd_edrfs_dirpage_t  *page,
					    int                    index,
					    nasd_edrfs_dirent_t   *dirent);

/* change the name of an entry. the new name _must_ take up no more
   slots than the old. */
nasd_status_t nasd_edrfs_dir_rename_entry(nasd_edrfs_dirpage_t  *page,
					  int                    slot,
					  char                  *newname);

/* add an entry to the given dirpage, returning the slot the entry was
   added to. fails and returns -1 if there's no room. */
int nasd_edrfs_dir_add_entry(nasd_edrfs_dirpage_t  *page,
				       char                  *name,
				       nasd_identifier_t      nasdid,
				       int                    type);

/* remove an entry from the given page. fails if the entry doesn't exist. */
nasd_status_t nasd_edrfs_dir_remove_entry(nasd_edrfs_dirpage_t  *page,
					  char                  *name);


/* compact a page to reduce fragmentation -- moves all entries to the
   start of the page. */
void nasd_edrfs_dir_compact_page(nasd_edrfs_dirpage_t *page);

/* set up an empty directory page */
void nasd_edrfs_dir_init_page(nasd_edrfs_dirpage_t *page);

/* debugging functions */
void nasd_edrfs_dir_dump_header(nasd_edrfs_dirpage_t *page);

void nasd_edrfs_dir_dump_dirslot(nasd_edrfs_dirpage_t *page, int slot);

#endif /* _NASD__NASD_EDRFS_DIR_H_ */
