Home | History | Annotate | Line # | Download | only in efs
      1  1.2  msaitoh /*	$NetBSD: efs_dir.h,v 1.2 2016/07/07 06:55:42 msaitoh Exp $	*/
      2  1.1   rumble 
      3  1.1   rumble /*
      4  1.1   rumble  * Copyright (c) 2006 Stephen M. Rumble <rumble (at) ephemeral.org>
      5  1.1   rumble  *
      6  1.1   rumble  * Permission to use, copy, modify, and distribute this software for any
      7  1.1   rumble  * purpose with or without fee is hereby granted, provided that the above
      8  1.1   rumble  * copyright notice and this permission notice appear in all copies.
      9  1.1   rumble  *
     10  1.1   rumble  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  1.1   rumble  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  1.1   rumble  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  1.1   rumble  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  1.1   rumble  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15  1.1   rumble  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16  1.1   rumble  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  1.1   rumble  */
     18  1.1   rumble 
     19  1.1   rumble /*
     20  1.1   rumble  * EFS directory block and directory entry formats.
     21  1.1   rumble  *
     22  1.1   rumble  * See IRIX dir(4)
     23  1.1   rumble  */
     24  1.1   rumble 
     25  1.1   rumble #ifndef _FS_EFS_EFS_DIR_H_
     26  1.1   rumble #define _FS_EFS_EFS_DIR_H_
     27  1.1   rumble 
     28  1.1   rumble /*
     29  1.1   rumble  * EFS directory block (512 bytes on disk)
     30  1.1   rumble  */
     31  1.1   rumble 
     32  1.1   rumble #define EFS_DIRBLK_MAGIC	0xbeef
     33  1.1   rumble #define EFS_DIRBLK_SIZE		EFS_BB_SIZE
     34  1.1   rumble #define EFS_DIRBLK_HEADER_SIZE	4
     35  1.1   rumble #define EFS_DIRBLK_SPACE_SIZE	(EFS_DIRBLK_SIZE - EFS_DIRBLK_HEADER_SIZE)
     36  1.1   rumble 
     37  1.1   rumble struct efs_dirblk {
     38  1.1   rumble 	uint16_t	db_magic;	/* must be EFS_DIRBLK_MAGIC */
     39  1.1   rumble 	uint8_t		db_firstused;	/* first dir entry offset (compacted) */
     40  1.1   rumble 	uint8_t		db_slots;	/* total number of entry offsets */
     41  1.1   rumble 
     42  1.1   rumble 	/*
     43  1.1   rumble 	 * The following db_space is used for three things:
     44  1.1   rumble 	 *  1) Array of entry offsets, one byte each, relative to the
     45  1.1   rumble 	 *     efs_dirblk structure (not db_space!). These are stored right
     46  1.1   rumble 	 *     shifted by one, thus providing 9 bits to address the entries.
     47  1.1   rumble 	 *  2) Array of even-sized directory entries, which exist at even
     48  1.1   rumble 	 *     offsets, of course.
     49  1.1   rumble 	 *  3) Free space between the two arrays used for expanding either.
     50  1.1   rumble 	 *
     51  1.1   rumble 	 * The entry offsets exist in the lower offset range of de_space,
     52  1.1   rumble 	 * followed by efs_dirent structures higher up:
     53  1.1   rumble 	 *
     54  1.1   rumble 	 *  db_space[sizeof(db_space)]  _______________________  _
     55  1.1   rumble 	 *                             |                       |  |
     56  1.1   rumble 	 *                             |  efs_dirent at z << 1 |  |
     57  1.1   rumble 	 *                             |_______________________|  |
     58  1.1   rumble 	 *                             |                       |  |
     59  1.1   rumble 	 *                             |  efs_dirent at x << 1 |  |-- directory
     60  1.1   rumble 	 *                             |                       |  |    entries
     61  1.1   rumble 	 *                             |_______________________|  |
     62  1.1   rumble 	 *                             |                       |  |
     63  1.1   rumble 	 *                             |  efs_dirent at y << 1 |  |
     64  1.1   rumble 	 * db_space[db_firstused << 1] |_______________________| _|
     65  1.1   rumble 	 *                             |          ...          |
     66  1.1   rumble          *                             |       free space      |
     67  1.1   rumble 	 *                             |          ...          |
     68  1.1   rumble 	 *          db_space[db_slots] |_______________________| _
     69  1.1   rumble 	 *                             |___________z___________|  |
     70  1.1   rumble 	 *                             |___________0___________|  |-- directory
     71  1.1   rumble 	 *                             |___________y___________|  |    entry
     72  1.1   rumble 	 *                 db_space[0] |___________x___________| _|     offsets
     73  1.1   rumble 	 *
     74  1.1   rumble 	 * In the above diagram, db_firstused would be equal to y. Note that
     75  1.1   rumble 	 * directory entry offsets need not occur in the same order as their
     76  1.1   rumble 	 * corresponding entries. The size of the offset array is indicated
     77  1.1   rumble 	 * by 'db_slots'. Unused slots in the middle of the array are zeroed.
     78  1.1   rumble 	 *
     79  1.1   rumble 	 * A range of free space between the end of the offset array and the
     80  1.1   rumble 	 * first directory entry is used for allocating new entry offsets and
     81  1.1   rumble 	 * directory entries. Its size is equal to ('db_firstused' << 1) -
     82  1.1   rumble 	 * 'db_slots'.
     83  1.1   rumble 	 *
     84  1.1   rumble 	 * When a directory entry is added, the directory offset array is
     85  1.1   rumble 	 * searched for a zeroed entry to use. If none is available and space
     86  1.1   rumble 	 * permits, it is allocated from the bottom of the free space region
     87  1.1   rumble 	 * and 'db_slots' is incremented. The space for the directory entry is
     88  1.1   rumble 	 * allocated from the top of free space, and the offset is stored.
     89  1.1   rumble 	 *
     90  1.1   rumble 	 * When a directory entry is removed, all directory entries below it
     91  1.1   rumble 	 * are moved up in order to expand the free space region. If the
     92  1.1   rumble 	 * corresponding entry offset borders the free space (it is last in the
     93  1.1   rumble 	 * array), it is coalesced into the free space region and 'db_slots' is
     94  1.1   rumble 	 * decremented.
     95  1.1   rumble 	 *
     96  1.1   rumble 	 * XXX when all entries removed, (how) do we free the dirblk?
     97  1.1   rumble 	 *
     98  1.1   rumble 	 * According to IRIX dir(4), the offset of a directory entry's offset
     99  1.1   rumble 	 * within the array of offsets does not change (say what?). That is, if
    100  1.1   rumble 	 * directory entry P's offset is contained in db_space[3], it will
    101  1.1   rumble 	 * remain in db_space[3] until it is removed. In other words, they do
    102  1.1   rumble 	 * not reshuffle the entry offsets in order to coalesce the unused
    103  1.1   rumble 	 * offset array entries into the free space region. Since we allocate
    104  1.1   rumble 	 * from zeroed ones before dipping into free space, this is typically
    105  1.1   rumble 	 * not a problem. However, it leaves open the case where many older
    106  1.1   rumble 	 * files are removed, thus leaving a valid array offset at the top,
    107  1.1   rumble 	 * which reduces free space and potentially keeps a large directory
    108  1.1   rumble 	 * entry from being added. Since there's no technical reason why moving
    109  1.1   rumble 	 * them around would violate the format, I'm guessing that IRIX does
    110  1.1   rumble 	 * some sort of caching of index offsets within the array. A few quick
    111  1.1   rumble 	 * tests seems to indicate that coalescing can be slightly more
    112  1.1   rumble 	 * performant. One could also sort array offsets by de_namelen and
    113  1.1   rumble 	 * binary search on lookup, but I am not sure how much performance could
    114  1.1   rumble 	 * be gained since there are only 72 entries at maximum, far less on
    115  1.1   rumble 	 * average, and many unix files have similar length. Quick tests show
    116  1.1   rumble 	 * no appreciable difference when using binary search, as one would
    117  1.1   rumble 	 * suspect.
    118  1.1   rumble 	 */
    119  1.1   rumble 	uint8_t		db_space[EFS_DIRBLK_SPACE_SIZE];
    120  1.2  msaitoh } __packed;
    121  1.1   rumble 
    122  1.1   rumble /*
    123  1.1   rumble  * 'db_slots' (directory entry offset array size) can be no larger
    124  1.1   rumble  * than (EFS_DIRBLK_SPACE_SIZE / 9), as each efs_dirent struct is
    125  1.1   rumble  * minimally 6 bytes and requires one 1-byte offset entry.
    126  1.1   rumble  */
    127  1.1   rumble #define EFS_DIRBLK_SLOTS_MAX	(EFS_DIRBLK_SPACE_SIZE / 7)
    128  1.1   rumble 
    129  1.1   rumble #define EFS_DIRBLK_SLOT_FREE	(0)	/* free, uncoalesced slots are zeroed */
    130  1.1   rumble 
    131  1.1   rumble /*
    132  1.1   rumble  * Directory entry structure, which resides in efs_dirblk->space. Minimally
    133  1.1   rumble  * 6 bytes on-disk, maximally 260 bytes.
    134  1.1   rumble  *
    135  1.1   rumble  * The allocation within efs_dirblk->space must always be even, so the
    136  1.1   rumble  * structure is always padded by one byte if the efs_dirent struct is odd. This
    137  1.1   rumble  * occurs when de_namelen is even. The macros below handle this irregularity. It
    138  1.1   rumble  * should be noted that despite this, de_namelen will always reflect the true
    139  1.1   rumble  * length of de_name, which is NOT nul-terminated. Therefore without a priori
    140  1.1   rumble  * knowledge of this scheme, one cannot accurately calculate the efs_dirent size
    141  1.1   rumble  * based on the de_namelen field alone, rather EFS_DIRENT_SIZE() must be used.
    142  1.1   rumble  */
    143  1.1   rumble struct efs_dirent {
    144  1.1   rumble 	/* entry's inode number */
    145  1.1   rumble 	union {
    146  1.1   rumble 		uint32_t l;
    147  1.1   rumble 		uint16_t s[2];
    148  1.1   rumble 	} de_u;
    149  1.1   rumble 
    150  1.1   rumble 	/*
    151  1.1   rumble 	 * de_name is of variable length (1 <= de_namelen <= 255). Note that
    152  1.1   rumble 	 * the string is NOT nul-terminated.
    153  1.1   rumble 	 */
    154  1.1   rumble 	uint8_t		de_namelen;
    155  1.1   rumble 	char		de_name[1];	/* variably sized */
    156  1.2  msaitoh } __packed;
    157  1.1   rumble 
    158  1.1   rumble #define de_inumber	de_u.l
    159  1.1   rumble 
    160  1.1   rumble #define EFS_DIRBLK_TO_DIRENT(_d, _o)	(struct efs_dirent *)((char *)(_d) + _o)
    161  1.1   rumble 
    162  1.1   rumble /*
    163  1.1   rumble  * Offsets are stored on-disk right shifted one to squeeze 512 even-byte
    164  1.1   rumble  * boundary offsets into a uint8_t. Before being compacted, the least
    165  1.1   rumble  * significant bits of an offset must, of course, be zero.
    166  1.1   rumble  */
    167  1.1   rumble #define EFS_DIRENT_OFF_SHFT		1
    168  1.1   rumble #define EFS_DIRENT_OFF_EXPND(_x)	((_x) << EFS_DIRENT_OFF_SHFT)
    169  1.1   rumble #define EFS_DIRENT_OFF_COMPT(_x)	((_x) >> EFS_DIRENT_OFF_SHFT)
    170  1.1   rumble #define EFS_DIRENT_OFF_VALID(_x)	(((_x) & 0x1) == 0 && (_x) < \
    171  1.1   rumble 					 EFS_DIRBLK_SPACE_SIZE) /*if expanded*/
    172  1.1   rumble 
    173  1.1   rumble #define EFS_DIRENT_NAMELEN_MAX		255
    174  1.1   rumble 
    175  1.1   rumble #define EFS_DIRENT_SIZE_MIN	(sizeof(struct efs_dirent))
    176  1.1   rumble #define EFS_DIRENT_SIZE_MAX	(EFS_DIRENT_SIZE_MIN+EFS_DIRENT_NAMELEN_MAX - 1)
    177  1.1   rumble 
    178  1.1   rumble /*
    179  1.1   rumble  * Calculate the size of struct efs_dirent given the provided namelen. If our
    180  1.1   rumble  * namelen were even, then struct efs_dirent's size would be odd. In such a case
    181  1.1   rumble  * we must pad to ensure 16-bit alignment of the structure.
    182  1.1   rumble  */
    183  1.1   rumble #define EFS_DIRENT_SIZE(_x)	(EFS_DIRENT_SIZE_MIN + (_x) - ((_x) & 0x1))
    184  1.1   rumble 
    185  1.1   rumble #endif /* !_FS_EFS_EFS_DIR_H_ */
    186