119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o/*
219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * icount.c --- an efficient inode count abstraction
319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * Copyright (C) 1997 Theodore Ts'o.
519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
7543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library
8543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2.
919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
1019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o */
1119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
124cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
1319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o#include <unistd.h>
144cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
1519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o#include <string.h>
1619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o#include <stdio.h>
171b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o#include <sys/stat.h>
181b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o#include <fcntl.h>
191b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o#include <errno.h>
2019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
21b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
2219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o#include "ext2fs.h"
231b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o#include "tdb.h"
2419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
2519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o/*
2619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * The data storage strategy used by icount relies on the observation
2719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * that most inode counts are either zero (for non-allocated inodes),
2819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * one (for most files), and only a few that are two or more
2919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * (directories and files that are linked to more than one directory).
3019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
3119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * Also, e2fsck tends to load the icount data sequentially.
3219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
3319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * So, we use an inode bitmap to indicate which inodes have a count of
3419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * one, and then use a sorted list to store the counts for inodes
3519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * which are greater than one.
3619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
3719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * We also use an optional bitmap to indicate which inodes are already
3819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * in the sorted list, to speed up the use of this abstraction by
3919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * e2fsck's pass 2.  Pass 2 increments inode counts as it finds them,
4019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * so this extra bitmap avoids searching the sorted list to see if a
4119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * particular inode is on the sorted list already.
4219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o */
4319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
4419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostruct ext2_icount_el {
4531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	ext2_ino_t	ino;
4660bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o	__u32		count;
4719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o};
4819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
4919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostruct ext2_icount {
503cb6c5021d722e17b7105d1bc090880671f6fc6dTheodore Ts'o	errcode_t		magic;
5119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	ext2fs_inode_bitmap	single;
5219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	ext2fs_inode_bitmap	multiple;
5331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	ext2_ino_t		count;
5431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	ext2_ino_t		size;
5531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	ext2_ino_t		num_inodes;
56544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ext2_ino_t		cursor;
5719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	struct ext2_icount_el	*list;
581b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	struct ext2_icount_el	*last_lookup;
591b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	char			*tdb_fn;
601b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	TDB_CONTEXT		*tdb;
6119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o};
6219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
6360bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o/*
6460bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o * We now use a 32-bit counter field because it doesn't cost us
6560bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o * anything extra for the in-memory data structure, due to alignment
6660bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o * padding.  But there's no point changing the interface if most of
6760bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o * the time we only care if the number is bigger than 65,000 or not.
6860bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o * So use the following translation function to return a 16-bit count.
6960bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o */
7060bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o#define icount_16_xlate(x) (((x) > 65500) ? 65500 : (x))
7160bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o
7219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ovoid ext2fs_free_icount(ext2_icount_t icount)
7319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
7419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (!icount)
7519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return;
7619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
7719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	icount->magic = 0;
7819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (icount->list)
79c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&icount->list);
8019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (icount->single)
8119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		ext2fs_free_inode_bitmap(icount->single);
8219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (icount->multiple)
8319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		ext2fs_free_inode_bitmap(icount->multiple);
841b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (icount->tdb)
851b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		tdb_close(icount->tdb);
861b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (icount->tdb_fn) {
871b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		unlink(icount->tdb_fn);
881b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		free(icount->tdb_fn);
891b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	}
901b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
91c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&icount);
9219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
9319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
941b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'ostatic errcode_t alloc_icount(ext2_filsys fs, int flags, ext2_icount_t *ret)
9519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
9619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	ext2_icount_t	icount;
9719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	errcode_t	retval;
9819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
991b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	*ret = 0;
1001b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
101c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount);
1027b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
1037b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
10419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	memset(icount, 0, sizeof(struct ext2_icount));
10519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
106e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_allocate_inode_bitmap(fs, "icount", &icount->single);
10719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (retval)
10819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		goto errout;
10919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
11019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (flags & EXT2_ICOUNT_OPT_INCREMENT) {
111e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_allocate_inode_bitmap(fs, "icount_inc",
11219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o						      &icount->multiple);
11319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (retval)
11419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			goto errout;
11519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	} else
11619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		icount->multiple = 0;
11719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
1181b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	icount->magic = EXT2_ET_MAGIC_ICOUNT;
1191b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	icount->num_inodes = fs->super->s_inodes_count;
1201b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1211b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	*ret = icount;
1221b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	return 0;
1231b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1241b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'oerrout:
1251b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	ext2fs_free_icount(icount);
1261b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	return(retval);
1271b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o}
1281b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1291b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'ostruct uuid {
1301b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	__u32	time_low;
1311b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	__u16	time_mid;
1321b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	__u16	time_hi_and_version;
1331b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	__u16	clock_seq;
1341b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	__u8	node[6];
1351b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o};
1361b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1371b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'ostatic void unpack_uuid(void *in, struct uuid *uu)
1381b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o{
1391b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	__u8	*ptr = in;
1401b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	__u32	tmp;
1411b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1421b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	tmp = *ptr++;
1431b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	tmp = (tmp << 8) | *ptr++;
1441b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	tmp = (tmp << 8) | *ptr++;
1451b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	tmp = (tmp << 8) | *ptr++;
1461b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	uu->time_low = tmp;
1471b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1481b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	tmp = *ptr++;
1491b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	tmp = (tmp << 8) | *ptr++;
1501b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	uu->time_mid = tmp;
1511b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1521b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	tmp = *ptr++;
1531b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	tmp = (tmp << 8) | *ptr++;
1541b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	uu->time_hi_and_version = tmp;
1551b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1561b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	tmp = *ptr++;
1571b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	tmp = (tmp << 8) | *ptr++;
1581b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	uu->clock_seq = tmp;
1591b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1601b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	memcpy(uu->node, ptr, 6);
1611b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o}
1621b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1631b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'ostatic void uuid_unparse(void *uu, char *out)
1641b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o{
1651b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	struct uuid uuid;
1661b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1671b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	unpack_uuid(uu, &uuid);
1681b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	sprintf(out,
1691b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1701b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
1711b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
1721b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		uuid.node[0], uuid.node[1], uuid.node[2],
1731b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		uuid.node[3], uuid.node[4], uuid.node[5]);
1741b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o}
1751b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1761b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'oerrcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir,
1771b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o				   int flags, ext2_icount_t *ret)
1781b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o{
1791b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	ext2_icount_t	icount;
1801b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	errcode_t	retval;
1811b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	char 		*fn, uuid[40];
182e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2_ino_t	num_inodes;
1831b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	int		fd;
1841b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1851b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	retval = alloc_icount(fs, flags,  &icount);
1861b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (retval)
1871b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		return retval;
1881b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
1891b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	retval = ext2fs_get_mem(strlen(tdb_dir) + 64, &fn);
1901b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (retval)
1911b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		goto errout;
1921b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	uuid_unparse(fs->super->s_uuid, uuid);
1931b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	sprintf(fn, "%s/%s-icount-XXXXXX", tdb_dir, uuid);
1941b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	fd = mkstemp(fn);
195e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (fd < 0)
196e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return fd;
197e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
198e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/*
199e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * This is an overestimate of the size that we will need; the
200e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * ideal value is the number of used inodes with a count
201e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * greater than 1.  OTOH the times when we really need this is
202e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * with the backup programs that use lots of hard links, in
203e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * which case the number of inodes in use approaches the ideal
204e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * value.
205e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 */
206e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	num_inodes = fs->super->s_inodes_count - fs->super->s_free_inodes_count;
2074e523bbe00cfa0240b4581eeca0c097b05c9fe3eTheodore Ts'o
2081b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	icount->tdb_fn = fn;
209e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	icount->tdb = tdb_open(fn, num_inodes, TDB_NOLOCK | TDB_NOSYNC,
2101b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			       O_RDWR | O_CREAT | O_TRUNC, 0600);
2111b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (icount->tdb) {
2121b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		close(fd);
2131b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		*ret = icount;
2141b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		return 0;
2151b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	}
2161b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
2171b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	retval = errno;
2181b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	close(fd);
2191b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
2201b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'oerrout:
2211b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	ext2fs_free_icount(icount);
2221b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	return(retval);
2231b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o}
2241b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
2251b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'oerrcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,
2261b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o				ext2_icount_t hint, ext2_icount_t *ret)
2271b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o{
2281b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	ext2_icount_t	icount;
2291b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	errcode_t	retval;
2301b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	size_t		bytes;
2311b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	ext2_ino_t	i;
2321b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
2331b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (hint) {
2341b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT);
2351b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		if (hint->size > size)
2361b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			size = (size_t) hint->size;
2371b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	}
2381b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
2391b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	retval = alloc_icount(fs, flags, &icount);
2401b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (retval)
2411b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		return retval;
2421b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
24319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (size) {
24419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		icount->size = size;
24519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	} else {
24619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		/*
24719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 * Figure out how many special case inode counts we will
24819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 * have.  We know we will need one for each directory;
24919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 * we also need to reserve some extra room for file links
25019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 */
25119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		retval = ext2fs_get_num_dirs(fs, &icount->size);
25219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (retval)
25319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			goto errout;
25419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		icount->size += fs->super->s_inodes_count / 50;
25519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
2561b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
2573cb6c5021d722e17b7105d1bc090880671f6fc6dTheodore Ts'o	bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el));
25819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o#if 0
259d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen	printf("Icount allocated %u entries, %d bytes.\n",
26019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	       icount->size, bytes);
26119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o#endif
262ee01079a17bfecd17292ccd60058056fb3a8ba6cTheodore Ts'o	retval = ext2fs_get_array(icount->size, sizeof(struct ext2_icount_el),
263ee01079a17bfecd17292ccd60058056fb3a8ba6cTheodore Ts'o			 &icount->list);
2647b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
26519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		goto errout;
26619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	memset(icount->list, 0, bytes);
26719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
26819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	icount->count = 0;
26919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	icount->cursor = 0;
27019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
271521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	/*
272521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	 * Populate the sorted list with those entries which were
273521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	 * found in the hint icount (since those are ones which will
274521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	 * likely need to be in the sorted list this time around).
275521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	 */
276521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (hint) {
277521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		for (i=0; i < hint->count; i++)
278521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o			icount->list[i].ino = hint->list[i].ino;
279521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		icount->count = hint->count;
280521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	}
28119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
282521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	*ret = icount;
28319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	return 0;
28419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
28519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'oerrout:
28619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	ext2fs_free_icount(icount);
28719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	return(retval);
28819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
28919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
2901b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'oerrcode_t ext2fs_create_icount(ext2_filsys fs, int flags,
291544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			       unsigned int size,
292521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o			       ext2_icount_t *ret)
29319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
294521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	return ext2fs_create_icount2(fs, flags, size, 0, ret);
29519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
29619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
29719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o/*
298521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o * insert_icount_el() --- Insert a new entry into the sorted list at a
299521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o * 	specified position.
30019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o */
301521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'ostatic struct ext2_icount_el *insert_icount_el(ext2_icount_t icount,
30231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    ext2_ino_t ino, int pos)
30319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
3047b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	struct ext2_icount_el 	*el;
3057b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
3061b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	ext2_ino_t		new_size = 0;
307521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	int			num;
30819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
3091b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (icount->last_lookup && icount->last_lookup->ino == ino)
3101b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		return icount->last_lookup;
3111b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
31219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (icount->count >= icount->size) {
31319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (icount->count) {
3143cb6c5021d722e17b7105d1bc090880671f6fc6dTheodore Ts'o			new_size = icount->list[(unsigned)icount->count-1].ino;
3151b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			new_size = (ext2_ino_t) (icount->count *
31630e50b7cdd6f5bbd5f2d6a2ee8ce0d4522336397Theodore Ts'o				((float) icount->num_inodes / new_size));
31719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		}
31819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (new_size < (icount->size + 100))
31919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			new_size = icount->size + 100;
32019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o#if 0
321d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen		printf("Reallocating icount %u entries...\n", new_size);
3221b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o#endif
32376f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o		retval = ext2fs_resize_mem((size_t) icount->size *
32476f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o					   sizeof(struct ext2_icount_el),
32576f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o					   (size_t) new_size *
3267b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o					   sizeof(struct ext2_icount_el),
327c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o					   &icount->list);
3287b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		if (retval)
32919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			return 0;
33019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		icount->size = new_size;
33119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
3323cb6c5021d722e17b7105d1bc090880671f6fc6dTheodore Ts'o	num = (int) icount->count - pos;
333521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (num < 0)
334521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		return 0;	/* should never happen */
335521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (num) {
336521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		memmove(&icount->list[pos+1], &icount->list[pos],
337521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o			sizeof(struct ext2_icount_el) * num);
338521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	}
339521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	icount->count++;
340521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	el = &icount->list[pos];
341521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	el->count = 0;
342521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	el->ino = ino;
3431b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	icount->last_lookup = el;
344521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	return el;
345521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o}
346521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o
347521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o/*
348521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o * get_icount_el() --- given an inode number, try to find icount
349521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o * 	information in the sorted list.  If the create flag is set,
350521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o * 	and we can't find an entry, create one in the sorted list.
351521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o */
352521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'ostatic struct ext2_icount_el *get_icount_el(ext2_icount_t icount,
35331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    ext2_ino_t ino, int create)
354521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o{
355521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	int	low, high, mid;
356521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o
357521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (!icount || !icount->list)
358521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		return 0;
35919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
360521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (create && ((icount->count == 0) ||
3613cb6c5021d722e17b7105d1bc090880671f6fc6dTheodore Ts'o		       (ino > icount->list[(unsigned)icount->count-1].ino))) {
3623cb6c5021d722e17b7105d1bc090880671f6fc6dTheodore Ts'o		return insert_icount_el(icount, ino, (unsigned) icount->count);
363521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	}
364521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (icount->count == 0)
365521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		return 0;
3661b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
367521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (icount->cursor >= icount->count)
368521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		icount->cursor = 0;
369521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (ino == icount->list[icount->cursor].ino)
370521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		return &icount->list[icount->cursor++];
371521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o#if 0
372521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	printf("Non-cursor get_icount_el: %u\n", ino);
373521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o#endif
374521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	low = 0;
3753cb6c5021d722e17b7105d1bc090880671f6fc6dTheodore Ts'o	high = (int) icount->count-1;
376521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	while (low <= high) {
377e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		mid = ((unsigned)low + (unsigned)high) >> 1;
378521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		if (ino == icount->list[mid].ino) {
379521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o			icount->cursor = mid+1;
380521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o			return &icount->list[mid];
381521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		}
382521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		if (ino < icount->list[mid].ino)
383521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o			high = mid-1;
384521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		else
385521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o			low = mid+1;
386521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	}
38719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	/*
388521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	 * If we need to create a new entry, it should be right at
389521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	 * low (where high will be left at low-1).
39019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	 */
391521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (create)
392521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		return insert_icount_el(icount, ino, low);
393521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	return 0;
394521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o}
395521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o
3961b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'ostatic errcode_t set_inode_count(ext2_icount_t icount, ext2_ino_t ino,
39760bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o				 __u32 count)
3981b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o{
3991b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	struct ext2_icount_el 	*el;
4001b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	TDB_DATA key, data;
4011b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
4021b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (icount->tdb) {
4031b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		key.dptr = (unsigned char *) &ino;
4041b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		key.dsize = sizeof(ext2_ino_t);
4051b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		data.dptr = (unsigned char *) &count;
40660bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o		data.dsize = sizeof(__u32);
4071b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		if (count) {
4081b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			if (tdb_store(icount->tdb, key, data, TDB_REPLACE))
4091b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o				return tdb_error(icount->tdb) +
4101b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o					EXT2_ET_TDB_SUCCESS;
4111b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		} else {
4121b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			if (tdb_delete(icount->tdb, key))
4131b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o				return tdb_error(icount->tdb) +
4141b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o					EXT2_ET_TDB_SUCCESS;
4151b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		}
4161b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		return 0;
4171b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	}
4181b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
4191b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	el = get_icount_el(icount, ino, 1);
4201b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (!el)
4211b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		return EXT2_ET_NO_MEMORY;
4221b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
4231b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	el->count = count;
4241b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	return 0;
4251b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o}
4261b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
4271b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'ostatic errcode_t get_inode_count(ext2_icount_t icount, ext2_ino_t ino,
42860bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o				 __u32 *count)
4291b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o{
4301b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	struct ext2_icount_el 	*el;
4311b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	TDB_DATA key, data;
4321b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
4331b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (icount->tdb) {
4341b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		key.dptr = (unsigned char *) &ino;
4351b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		key.dsize = sizeof(ext2_ino_t);
4361b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
4371b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		data = tdb_fetch(icount->tdb, key);
4381b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		if (data.dptr == NULL) {
4391b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			*count = 0;
4401b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			return tdb_error(icount->tdb) + EXT2_ET_TDB_SUCCESS;
4411b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		}
4421b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
44360bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o		*count = *((__u32 *) data.dptr);
444a1f642728fe6fd2c361343fec349808ea8a524f4Theodore Ts'o		free(data.dptr);
4451b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		return 0;
4461b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	}
4471b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	el = get_icount_el(icount, ino, 0);
4481b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (!el) {
4491b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		*count = 0;
4501b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		return ENOENT;
4511b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	}
4521b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
4531b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	*count = el->count;
4541b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	return 0;
4551b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o}
4561b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
457521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'oerrcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out)
458521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o{
459521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	errcode_t	ret = 0;
460544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	i;
461521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	const char *bad = "bad icount";
4621b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
463521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
464521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o
465521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (icount->count > icount->size) {
466521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		fprintf(out, "%s: count > size\n", bad);
4671f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o		return EXT2_ET_INVALID_ARGUMENT;
468521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	}
469521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	for (i=1; i < icount->count; i++) {
470521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		if (icount->list[i-1].ino >= icount->list[i].ino) {
47131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n",
472521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o				bad, i-1, icount->list[i-1].ino,
473521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o				i, icount->list[i].ino);
4741f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o			ret = EXT2_ET_INVALID_ARGUMENT;
47519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		}
47619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
477521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	return ret;
47819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
47919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
48031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oerrcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
48119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
48260bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o	__u32	val;
48319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
48419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
485521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (!ino || (ino > icount->num_inodes))
4861f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o		return EXT2_ET_INVALID_ARGUMENT;
487521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o
488e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
48919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		*ret = 1;
49019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return 0;
49119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
492521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (icount->multiple &&
493e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    !ext2fs_test_inode_bitmap2(icount->multiple, ino)) {
494521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		*ret = 0;
495521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		return 0;
496521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	}
49760bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o	get_inode_count(icount, ino, &val);
49860bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o	*ret = icount_16_xlate(val);
49919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	return 0;
50019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
50119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
50231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oerrcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
50319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				  __u16 *ret)
50419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
50560bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o	__u32			curr_value;
50619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
50719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
50819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
509521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (!ino || (ino > icount->num_inodes))
5101f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o		return EXT2_ET_INVALID_ARGUMENT;
511521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o
512e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
51319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		/*
51419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 * If the existing count is 1, then we know there is
515521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o		 * no entry in the list.
51619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 */
5171b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		if (set_inode_count(icount, ino, 2))
5181f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o			return EXT2_ET_NO_MEMORY;
5191b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		curr_value = 2;
520e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_unmark_inode_bitmap2(icount->single, ino);
52119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	} else if (icount->multiple) {
52219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		/*
52319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 * The count is either zero or greater than 1; if the
52419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 * inode is set in icount->multiple, then there should
5251b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		 * be an entry in the list, so we need to fix it.
52619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 */
527e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (ext2fs_test_inode_bitmap2(icount->multiple, ino)) {
5281b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			get_inode_count(icount, ino, &curr_value);
5291b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			curr_value++;
5301b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			if (set_inode_count(icount, ino, curr_value))
5311f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o				return EXT2_ET_NO_MEMORY;
53219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		} else {
53319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			/*
53419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			 * The count was zero; mark the single bitmap
53519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			 * and return.
53619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			 */
537e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			ext2fs_mark_inode_bitmap2(icount->single, ino);
53819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (ret)
53919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				*ret = 1;
54019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			return 0;
54119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		}
54219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	} else {
54319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		/*
54419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 * The count is either zero or greater than 1; try to
54519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 * find an entry in the list to determine which.
54619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		 */
5471b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		get_inode_count(icount, ino, &curr_value);
5481b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		curr_value++;
5491b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		if (set_inode_count(icount, ino, curr_value))
5501f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o			return EXT2_ET_NO_MEMORY;
551521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	}
55219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (icount->multiple)
553e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_mark_inode_bitmap2(icount->multiple, ino);
55419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ret)
55560bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o		*ret = icount_16_xlate(curr_value);
55619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	return 0;
55719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
55819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
55931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oerrcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
56019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				  __u16 *ret)
56119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
56260bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o	__u32			curr_value;
56319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
564521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (!ino || (ino > icount->num_inodes))
5651f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o		return EXT2_ET_INVALID_ARGUMENT;
566521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o
56719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
56819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
569e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
570e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_unmark_inode_bitmap2(icount->single, ino);
57119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (icount->multiple)
572e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			ext2fs_unmark_inode_bitmap2(icount->multiple, ino);
57319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		else {
5741b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			set_inode_count(icount, ino, 0);
57519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		}
57619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (ret)
57719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			*ret = 0;
57819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return 0;
57919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
58019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
581521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (icount->multiple &&
582e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    !ext2fs_test_inode_bitmap2(icount->multiple, ino))
5831f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o		return EXT2_ET_INVALID_ARGUMENT;
5841b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o
5851b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	get_inode_count(icount, ino, &curr_value);
5861b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (!curr_value)
5871f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o		return EXT2_ET_INVALID_ARGUMENT;
5881b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	curr_value--;
5891b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (set_inode_count(icount, ino, curr_value))
5901b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		return EXT2_ET_NO_MEMORY;
59119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
5921b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (curr_value == 1)
593e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_mark_inode_bitmap2(icount->single, ino);
5941b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if ((curr_value == 0) && icount->multiple)
595e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_unmark_inode_bitmap2(icount->multiple, ino);
59619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
59719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ret)
59860bbd1af533daf8c726d6e5e4f17b293494bd939Theodore Ts'o		*ret = icount_16_xlate(curr_value);
59919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	return 0;
60019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
60119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
60231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oerrcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
60319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			      __u16 count)
60419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
605521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o	if (!ino || (ino > icount->num_inodes))
6061f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o		return EXT2_ET_INVALID_ARGUMENT;
607521e36857227b21e7ab47b0a97f788d2af9f9717Theodore Ts'o
60819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
60919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
61019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (count == 1) {
611e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_mark_inode_bitmap2(icount->single, ino);
61219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (icount->multiple)
613e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			ext2fs_unmark_inode_bitmap2(icount->multiple, ino);
61419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return 0;
61519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
61619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (count == 0) {
617e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_unmark_inode_bitmap2(icount->single, ino);
61819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (icount->multiple) {
61919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			/*
62019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			 * If the icount->multiple bitmap is enabled,
62119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			 * we can just clear both bitmaps and we're done
62219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			 */
623e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			ext2fs_unmark_inode_bitmap2(icount->multiple, ino);
6241b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		} else
6251b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			set_inode_count(icount, ino, 0);
62619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return 0;
62719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
62819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
6291b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (set_inode_count(icount, ino, count))
6301f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o		return EXT2_ET_NO_MEMORY;
631e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_unmark_inode_bitmap2(icount->single, ino);
63219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (icount->multiple)
633e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_mark_inode_bitmap2(icount->multiple, ino);
63419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	return 0;
63519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
63619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
63731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount)
63819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
63919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT)
64019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return 0;
64119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
64219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	return icount->size;
64319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
6441cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
6451cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o#ifdef DEBUG
6461cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
6471cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'oext2_filsys	test_fs;
6481cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'oext2_icount_t	icount;
6491cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
6501cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o#define EXIT		0x00
6511cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o#define FETCH		0x01
6521cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o#define STORE		0x02
6531cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o#define INCREMENT	0x03
6541cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o#define DECREMENT	0x04
6551cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
6561cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'ostruct test_program {
6571cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	int		cmd;
6581cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	ext2_ino_t	ino;
6591cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	__u16		arg;
6601cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	__u16		expected;
6611cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o};
6621cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
6631cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'ostruct test_program prog[] = {
6641cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 42, 42, 42 },
6651cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 1,  1, 1 },
6661cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 2,  2, 2 },
6671cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 3,  3, 3 },
6681cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 10, 1, 1 },
6691cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 42, 0, 0 },
6701cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ INCREMENT, 5, 0, 1 },
6711cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ INCREMENT, 5, 0, 2 },
6721cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ INCREMENT, 5, 0, 3 },
6731cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ INCREMENT, 5, 0, 4 },
6741cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ DECREMENT, 5, 0, 3 },
6751cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ DECREMENT, 5, 0, 2 },
6761cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ DECREMENT, 5, 0, 1 },
6771cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ DECREMENT, 5, 0, 0 },
6781cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ FETCH, 10, 0, 1 },
6791cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ FETCH, 1, 0, 1 },
6801cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ FETCH, 2, 0, 2 },
6811cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ FETCH, 3, 0, 3 },
6821cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ INCREMENT, 1, 0, 2 },
6831cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ DECREMENT, 2, 0, 1 },
6841cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ DECREMENT, 2, 0, 0 },
6851cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ FETCH, 12, 0, 0 },
6861cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ EXIT, 0, 0, 0 }
6871cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o};
6881cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
6891cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'ostruct test_program extended[] = {
6901cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 1,  1, 1 },
6911cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 2,  2, 2 },
6921cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 3,  3, 3 },
6931cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 4,  4, 4 },
6941cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 5,  5, 5 },
6951cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 6,  1, 1 },
6961cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 7,  2, 2 },
6971cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 8,  3, 3 },
6981cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 9,  4, 4 },
6991cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 10, 5, 5 },
7001cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 11, 1, 1 },
7011cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 12, 2, 2 },
7021cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 13, 3, 3 },
7031cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 14, 4, 4 },
7041cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 15, 5, 5 },
7051cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 16, 1, 1 },
7061cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 17, 2, 2 },
7071cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 18, 3, 3 },
7081cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 19, 4, 4 },
7091cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 20, 5, 5 },
7101cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 21, 1, 1 },
7111cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 22, 2, 2 },
7121cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 23, 3, 3 },
7131cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 24, 4, 4 },
7141cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 25, 5, 5 },
7151cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 26, 1, 1 },
7161cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 27, 2, 2 },
7171cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 28, 3, 3 },
7181cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 29, 4, 4 },
7191cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ STORE, 30, 5, 5 },
7201cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	{ EXIT, 0, 0, 0 }
7211cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o};
7221cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
7231cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o/*
7241cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o * Setup the variables for doing the inode scan test.
7251cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o */
7261cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'ostatic void setup(void)
7271cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o{
7281cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	errcode_t	retval;
7291cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	struct ext2_super_block param;
7301cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
7311cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	initialize_ext2_error_table();
7321cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
7331cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	memset(&param, 0, sizeof(param));
734e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_blocks_count_set(&param, 12000);
7351cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
736e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, &param,
7371cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o				   test_io_manager, &test_fs);
7381cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	if (retval) {
7391cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		com_err("setup", retval,
7401cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			"while initializing filesystem");
7411cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		exit(1);
7421cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	}
7431cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	retval = ext2fs_allocate_tables(test_fs);
7441cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	if (retval) {
7451cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		com_err("setup", retval,
7461cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			"while allocating tables for test filesystem");
7471cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		exit(1);
7481cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	}
7491cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o}
7501cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
7511b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'oint run_test(int flags, int size, char *dir, struct test_program *prog)
7521cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o{
7531cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	errcode_t	retval;
7541cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	ext2_icount_t	icount;
7551cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	struct test_program *pc;
7561cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	__u16		result;
7571cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	int		problem = 0;
7581cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
7591b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (dir) {
7601b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		retval = ext2fs_create_icount_tdb(test_fs, dir,
7611b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o						  flags, &icount);
7621b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		if (retval) {
7631b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			com_err("run_test", retval,
7641b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o				"while creating icount using tdb");
7651b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			exit(1);
7661b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		}
7671b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	} else {
7681b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		retval = ext2fs_create_icount2(test_fs, flags, size, 0,
7691b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o					       &icount);
7701b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		if (retval) {
7711b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			com_err("run_test", retval, "while creating icount");
7721b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o			exit(1);
7731b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o		}
7741cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	}
7751cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	for (pc = prog; pc->cmd != EXIT; pc++) {
7761cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		switch (pc->cmd) {
7771cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		case FETCH:
7781cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			printf("icount_fetch(%u) = ", pc->ino);
7791cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			break;
7801cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		case STORE:
7811cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			retval = ext2fs_icount_store(icount, pc->ino, pc->arg);
7821cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			if (retval) {
7831cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o				com_err("run_test", retval,
7841cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o					"while calling icount_store");
7851cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o				exit(1);
7861cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			}
7871cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			printf("icount_store(%u, %u) = ", pc->ino, pc->arg);
7881cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			break;
7891cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		case INCREMENT:
7901cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			retval = ext2fs_icount_increment(icount, pc->ino, 0);
7911cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			if (retval) {
7921cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o				com_err("run_test", retval,
7931cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o					"while calling icount_increment");
7941cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o				exit(1);
7951cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			}
7961cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			printf("icount_increment(%u) = ", pc->ino);
7971cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			break;
7981cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		case DECREMENT:
7991cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			retval = ext2fs_icount_decrement(icount, pc->ino, 0);
8001cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			if (retval) {
8011cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o				com_err("run_test", retval,
8021cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o					"while calling icount_decrement");
8031cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o				exit(1);
8041cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			}
8051cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			printf("icount_decrement(%u) = ", pc->ino);
8061cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			break;
8071cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		}
8081cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		retval = ext2fs_icount_fetch(icount, pc->ino, &result);
8091cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		if (retval) {
8101cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			com_err("run_test", retval,
8111cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o				"while calling icount_fetch");
8121cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			exit(1);
8131cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		}
8141cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		printf("%u (%s)\n", result, (result == pc->expected) ?
8151cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		       "OK" : "NOT OK");
8161cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		if (result != pc->expected)
8171cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o			problem++;
8181cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	}
8191cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	printf("icount size is %u\n", ext2fs_get_icount_size(icount));
8201cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	retval = ext2fs_icount_validate(icount, stdout);
8211cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	if (retval) {
8221cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		com_err("run_test", retval, "while calling icount_validate");
8231cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		exit(1);
8241cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	}
8251cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	ext2fs_free_icount(icount);
8261cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	return problem;
8271cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o}
8281cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
8291cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
8301cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'oint main(int argc, char **argv)
8311cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o{
8321cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	int failed = 0;
8331cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o
8341cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	setup();
8351cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	printf("Standard icount run:\n");
8361b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	failed += run_test(0, 0, 0, prog);
8371cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	printf("\nMultiple bitmap test:\n");
8381b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, 0, prog);
8391cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	printf("\nResizing icount:\n");
8401b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	failed += run_test(0, 3, 0, extended);
8411b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	printf("\nStandard icount run with tdb:\n");
8421b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	failed += run_test(0, 0, ".", prog);
8431b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	printf("\nMultiple bitmap test with tdb:\n");
8441b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, ".", prog);
8451b9d8cb7057387afae106ffa662613205f07e131Theodore Ts'o	if (failed)
8461cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o		printf("FAILED!\n");
8471cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o	return failed;
8481cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o}
8491cb78d8433af774864c9d62a246e5edbc612b123Theodore Ts'o#endif
850