Esempio n. 1
0
/* open two files and test write */
static BOOL cmdTest4(const char *tail)
{
	int fd1 = -1, fd2 = -1;

	MSGLN("open /a ...");
	if ((fd1 = uffs_open("/a", UO_RDWR | UO_CREATE)) < 0) {
		MSGLN("Can't open /a");
		goto fail_exit;
	}

	MSGLN("open /b ...");
	if ((fd2 = uffs_open("/b", UO_RDWR | UO_CREATE)) < 0) {
		MSGLN("Can't open /b");
		uffs_close(fd1);
		goto fail_exit;
	}

	MSGLN("write (1) to /a ...");
	uffs_write(fd1, "Hello,", 6);
	MSGLN("write (1) to /b ...");
	uffs_write(fd2, "Hello,", 6);
	MSGLN("write (2) to /a ...");
	uffs_write(fd1, "World.", 6);
	MSGLN("write (2) to /b ...");
	uffs_write(fd2, "World.", 6);
	MSGLN("close /a ...");
	uffs_close(fd1);
	MSGLN("close /b ...");
	uffs_close(fd2);

	return TRUE;

fail_exit:
	return TRUE;
}
/** format [<mount>] */
static int cmd_format(int argc, char *argv[])
{
	URET ret;
	const char *mount = "/";
	uffs_Device *dev;
	UBOOL force = U_FALSE;

	if (argc > 1) {
		mount = argv[1];
		if (argc > 2 && strcmp(argv[2], "-f") == 0)
			force = U_TRUE;
	}
	MSGLN("Formating %s ... ", mount);

	dev = uffs_GetDeviceFromMountPoint(mount);
	if (dev == NULL) {
		MSGLN("Can't get device from mount point.");
		return -1;
	}
	else {
		ret = uffs_FormatDevice(dev, force);
		if (ret != U_SUCC) {
			MSGLN("Format fail.");
			return -1;
		}
		else {
			MSGLN("Format succ.");
		}
		uffs_PutDevice(dev);
	}

	return 0;
}
Esempio n. 3
0
byte UFFS_PrintDiskInfo(const CLS1_StdIOType *io)
{
	uffs_MountTable *m;
	//uffs_Device *d;
	int i, b = 0, g = 0;
	MSGLN("UFFS disk info:");
	m = get_flash_mount_table();
	while (m->dev)
	{
		MSGLN("Mount point: %s, start: %d, end: %d",
				m->mount, m->start_block, m->end_block);
		MSGLN("Space: %ld Used: %ld Free: %ld",
				uffs_space_total(m->mount), 
				uffs_space_used(m->mount), 
				uffs_space_free(m->mount));
		for(i = m->start_block; i <= m->end_block; i++)
		{
			if(uffs_FlashIsBadBlock(m->dev, i))
				b++;
			else
				g++;
		}
		MSGLN("Blocks: %d good: %d bad: %d (%d %%)", m->end_block - m->start_block + 1, g, b, b*100/(b+g));
		m++;
	}

	return ERR_OK;
}
/** rm <obj> */
static int cmd_rm(int argc, char *argv[])
{
	const char *name = NULL;
	int ret = 0;
	struct uffs_stat st;

	CHK_ARGC(2, 2);

	name = argv[1];

	ret = uffs_stat(name, &st);
	if (ret < 0) {
		MSGLN("Can't stat '%s'", name);
		return ret;
	}

	if (st.st_mode & US_IFDIR) {
		ret = uffs_rmdir(name);
	}
	else {
		ret = uffs_remove(name);
	}

	if (ret == 0)
		MSGLN("Delete '%s' succ.", name);
	else
		MSGLN("Delete '%s' fail!", name);

	return ret;
}
Esempio n. 5
0
static URET test_write_file(const char *file_name, int pos, int size)
{
	int ret = U_FAIL;
	int fd = -1;

	if ((fd = uffs_open(file_name, UO_RDWR|UO_CREATE)) < 0) {
		MSGLN("Can't open file %s for write.", file_name);
		goto test_exit;
	}

	if (uffs_seek(fd, pos, USEEK_SET) != pos) {
		MSGLN("Can't seek file %s at pos %d", file_name, pos);
		goto test_failed;
	}

	if (do_write_test_file(fd, size) == U_FAIL) {
		MSGLN("Write file %s failed.", file_name);
		goto test_failed;
	}
	ret = U_SUCC;

test_failed:
	uffs_close(fd);

test_exit:

	return ret;
}
Esempio n. 6
0
static URET test_append_file(const char *file_name, int size)
{
	int ret = U_FAIL;
	int fd = -1;

	if ((fd = uffs_open(file_name, UO_RDWR|UO_APPEND|UO_CREATE)) < 0) {
		MSGLN("Can't open file %s for append.", file_name);
		goto test_exit;
	}

	uffs_seek(fd, 0, USEEK_END);

	if (do_write_test_file(fd, size) == U_FAIL) {
		MSGLN("Write file %s failed.", file_name);
		goto test_failed;
	}
	ret = U_SUCC;

test_failed:
	uffs_close(fd);

test_exit:

	return ret;
}
Esempio n. 7
0
/* open two files and test write */
static int cmd_t4(int argc, char *argv[])
{
	int fd1 = -1, fd2 = -1;

	MSGLN("open /a ...");
	if ((fd1 = uffs_open("/a", UO_RDWR | UO_CREATE)) < 0) {
		MSGLN("Can't open /a");
		goto fail_exit;
	}

	MSGLN("open /b ...");
	if ((fd2 = uffs_open("/b", UO_RDWR | UO_CREATE)) < 0) {
		MSGLN("Can't open /b");
		uffs_close(fd1);
		goto fail_exit;
	}

	MSGLN("write (1) to /a ...");
	uffs_write(fd1, "Hello,", 6);
	MSGLN("write (1) to /b ...");
	uffs_write(fd2, "Hello,", 6);
	MSGLN("write (2) to /a ...");
	uffs_write(fd1, "World.", 6);
	MSGLN("write (2) to /b ...");
	uffs_write(fd2, "World.", 6);
	MSGLN("close /a ...");
	uffs_close(fd1);
	MSGLN("close /b ...");
	uffs_close(fd2);

	return 0;

fail_exit:
	return -1;
}
Esempio n. 8
0
/* test appending file */
static BOOL cmdTest5(const char *tail)
{
	int fd = -1;
	URET ret;
	char buf[100];
	const char *name;

	if (!tail) {
		return FALSE;
	}

	name = cli_getparam(tail, NULL);

	fd = uffs_open(name, UO_RDWR|UO_APPEND);
	if (fd < 0) {
		MSGLN("Can't open %s", name);
		goto fail;
	}

	sprintf(buf, "append test...");
	ret = uffs_write(fd, buf, strlen(buf));
	if (ret != strlen(buf)) {
		MSGLN("write file failed, %d/%d", ret, strlen(buf));
	}
	else {
		MSGLN("write %d bytes to file, content: %s", ret, buf);
	}

	uffs_close(fd);

fail:

	return TRUE;
}
static void print_params(void)
{
	MSGLN("Parameters summary:");
	MSGLN("  uffs image file: %s", conf_emu_filename);
	MSGLN("  page size: %d", conf_page_data_size);
	MSGLN("  page spare size: %d", conf_page_spare_size);
	MSGLN("  pages per block: %d", conf_pages_per_block);
	MSGLN("  total blocks: %d", conf_total_blocks);
	MSGLN("  ecc option: %d (%s)", conf_ecc_option, g_ecc_option_strings[conf_ecc_option]);
	MSGLN("  ecc size: %d%s", conf_ecc_size, conf_ecc_size == 0 ? " (auto)" : "");
	MSGLN("  bad block status offset: %d", conf_status_byte_offset);
	MSGLN("");
}
Esempio n. 10
0
/**
 * read and check seq file
 *	t_check_seq <fd> <size>
 */
static int cmd_tcheck_seq(int argc, char *argv[])
{
	int fd;
	int len, size;
	int ret = 0, r_ret = 0;
	long pos;
	u8 buf[MAX_TEST_BUF_LEN];
	int i;
	u8 x;

	CHK_ARGC(3, 3);

	if (sscanf(argv[1], "%d", &fd) != 1) {
		return -1;
	}

	if (sscanf(argv[2], "%d", &len) != 1) {
		return -1;
	}

	pos = uffs_tell(fd);
	while (len > 0) {
		size = (len > sizeof(buf) ? sizeof(buf) : len);
		if ((r_ret = uffs_read(fd, buf, size)) < 0) {
			MSGLN("Read fail! fd = %d, size = %d, pos = %ld", fd, size, pos);
			ret = -1;
			break;
		}

		// check seq
		for (i = 0; i < r_ret; i++) {
			x = (pos + SEQ_INIT + i) % SEQ_MOD_LEN;
			if (buf[i] != x) {
				MSGLN("Check fail! fd = %d, pos = %ld (expect 0x%02x but 0x%02x)\n", fd, pos + i, x, buf[i]);
				ret = -1;
				break;
			}
		}

		if (ret < 0)
			break;

		len -= r_ret;
		pos += r_ret;
	}

	return ret;
}
/** dump [<mount>] */
static int cmd_dump(int argc, char *argv[])
{
	uffs_Device *dev;
	uffs_FileEmu *emu;
	const char *mount = "/";
	const char *dump_file = "dump.txt";

	if (argc > 1) {
		mount = argv[1];
		if (argc > 2)
			dump_file = argv[2];
	}

	dev = uffs_GetDeviceFromMountPoint(mount);
	if (dev == NULL) {
		MSGLN("Can't get device from mount point %s", mount);
		return -1;
	}

	emu = (uffs_FileEmu *)(dev->attr->_private);
	emu->dump_fp = fopen(dump_file, "w");

	uffs_DumpDevice(dev, dump_msg_to_stdout);

	if (emu->dump_fp)
		fclose(emu->dump_fp);

	uffs_PutDevice(dev);

	return 0;
}
Esempio n. 12
0
static byte InitCmd(const CLS1_ConstStdIOType *io)
{
	uffs_SetupDebugOutputCLS(io);
	MSGLN("initializing UFFS");
	my_init_filesystem();
	return ERR_OK;
}
Esempio n. 13
0
static int cmd_t2(int argc, char *argv[])
{
	URET ret;
	MSGLN("Test return: %s !", (ret = DoTest2()) == U_SUCC ? "succ" : "failed");

	return (ret == U_SUCC) ? 0 : -1;
}
Esempio n. 14
0
/**
 * write random seq to file
 *	t_write_seq <fd> <size>
 */
static int cmd_twrite_seq(int argc, char *argv[])
{
	int fd;
	int len = 0, size = 0;
	long pos = 0;
	int ret = 0, w_ret = 0;
	u8 buf[MAX_TEST_BUF_LEN];

	CHK_ARGC(3, 3);
	if (sscanf(argv[1], "%d", &fd) != 1) {
		return -1;
	}

	if (sscanf(argv[2], "%d", &len) != 1) {
		return -1;
	}

	pos = uffs_tell(fd);
	while (len > 0) {
		size = (len < sizeof(buf) ? len : sizeof(buf));
		memcp_seq(buf, size, pos);
		if ((w_ret = uffs_write(fd, buf, size)) < 0) {
			MSGLN("write fail! fd = %d, size = %d, pos = %ld", fd, size, pos);
			ret = -1;
			break;
		}
		pos += w_ret;
		len -= w_ret;
	}

	if (ret == 0)
		cli_env_set('1', len);

	return ret;
}
Esempio n. 15
0
/* t_format : test format partition */
static int cmd_TestFormat(int argc, char *argv[])
{
	URET ret;
	const char *mount = "/";
	uffs_Device *dev;
	UBOOL force = U_FALSE;
	const char *test_file = "/a.txt";
	int fd;
	int rc = -1;

	if (argc > 1) {
		mount = argv[1];
		if (argc > 2 && strcmp(argv[2], "-f") == 0)
			force = U_TRUE;
	}

	fd = uffs_open(test_file, UO_RDWR | UO_CREATE);
	if (fd < 0) {
		MSGLN("can't create test file %s", test_file);
		goto ext;
	}

	MSGLN("Formating %s ... ", mount);

	dev = uffs_GetDeviceFromMountPoint(mount);
	if (dev == NULL) {
		MSGLN("Can't get device from mount point.");
		goto ext;
	}
	else {
		ret = uffs_FormatDevice(dev, force);
		if (ret != U_SUCC) {
			MSGLN("Format fail.");
		}
		else {
			MSGLN("Format succ.");
			rc = 0;
		}
		uffs_PutDevice(dev);
	}

	uffs_close(fd);  // this should fail on signature check !
ext:
	return rc;
}
/** mkdir <dir> */
static int cmd_mkdir(int argc, char *argv[])
{
	const char *name;

	CHK_ARGC(2, 0);

	name = argv[1];
	
	if (uffs_mkdir(name) < 0) {
		MSGLN("Create %s fail, err: %d", name, uffs_get_error());
		return -1;
	}
	else {
		MSGLN("Create %s succ.", name);
	}

	return 0;
}
Esempio n. 17
0
static URET DoTest2(void)
{
	int fd = -1;
	URET ret = U_FAIL;
	char buf[100], buf_1[100];

	fd = uffs_open("/abc/", UO_RDWR|UO_DIR);
	if (fd < 0) {
		MSGLN("Can't open dir abc, err: %d", uffs_get_error());
		MSGLN("Try to create a new one...");
		fd = uffs_open("/abc/", UO_RDWR|UO_CREATE|UO_DIR);
		if (fd < 0) {
			MSGLN("Can't create new dir /abc/");
			goto exit_test;
		}
		else {
			uffs_close(fd);
		}
	}
	else {
		uffs_close(fd);
	}
	
	sprintf(buf, "123456789ABCDEF");
	fd = uffs_open("/abc/test.txt", UO_RDONLY);
	if( fd < 0 ){
		fd = uffs_open("/abc/test.txt", UO_RDWR|UO_CREATE);
		if (fd < 0) {
			MSGLN("Can't open /abc/test.txt");
			goto exit_test;
		}

		ret = uffs_write(fd, buf, strlen(buf));
		MSGLN("write %d bytes to file, content: %s", ret, buf);

		ret = uffs_seek(fd, 3, USEEK_SET);
		MSGLN("new file position: %d", ret);

		memset(buf_1, 0, sizeof(buf_1));
	}
	else{
		ret = uffs_seek(fd, 3, USEEK_SET);
		ret = uffs_read(fd, buf_1, 5);
	}
	MSGLN("read %d bytes, content: %s", ret, buf_1);

	if (memcmp(buf + 3, buf_1, 5) != 0) {
		ret = U_FAIL;
	}
	else {
		ret = U_SUCC;
	}

	uffs_close(fd);

exit_test:

	return ret;
}
Esempio n. 18
0
static URET test_verify_file(const char *file_name, UBOOL noecc)
{
	int fd;
	int ret = U_FAIL;
	unsigned char buf[100];
	int i, pos, len;
	u8 x;

	if ((fd = uffs_open(file_name, (noecc ? UO_RDONLY|UO_NOECC : UO_RDONLY))) < 0) {
		MSGLN("Can't open file %s for read.", file_name);
		goto test_exit;
	}

	pos = 0;
	while (!uffs_eof(fd)) {
		len = uffs_read(fd, buf, sizeof(buf));
		if (len <= 0)
			goto test_failed;
		for (i = 0; i < len; i++) {
			x = (SEQ_INIT + pos + i) % SEQ_MOD_LEN;
			if (buf[i] != x) {
				MSGLN("Verify file %s failed at: %d, expect 0x%02x but got 0x%02x", file_name, pos + i, x, buf[i]);
				goto test_failed;
			}
		}
		pos += len;
	}

	if (pos != uffs_seek(fd, 0, USEEK_END)) {
		MSGLN("Verify file %s failed. invalid file length.", file_name);
		goto test_failed;
	}

	MSGLN("Verify file %s succ.", file_name);
	ret = U_SUCC;

test_failed:
	uffs_close(fd);

test_exit:

	return ret;
}
static void print_mount_points(void)
{
	struct uffs_MountTableEntrySt *m;

	m = &(conf_mounts[0]);
	while (m->dev) {
		MSGLN ("Mount point: %s, start: %d, end: %d", m->mount, m->start_block, m->end_block);
		m++;
	}
}
Esempio n. 20
0
static BOOL cmdTestFormat(const char *tail)
{
	URET ret;
	const char *mount = "/";
	uffs_Device *dev;
	const char *next;
	UBOOL force = U_FALSE;
	const char *test_file = "/a.txt";
	int fd;

	if (tail) {
		mount = cli_getparam(tail, &next);
		if (next && strcmp(next, "-f") == 0)
			force = U_TRUE;
	}

	fd = uffs_open(test_file, UO_RDWR | UO_CREATE);
	if (fd < 0) {
		MSGLN("can't create test file %s", test_file);
		return U_TRUE;
	}

	MSGLN("Formating %s ... ", mount);

	dev = uffs_GetDeviceFromMountPoint(mount);
	if (dev == NULL) {
		MSGLN("Can't get device from mount point.");
	}
	else {
		ret = uffs_FormatDevice(dev, force);
		if (ret != U_SUCC) {
			MSGLN("Format fail.");
		}
		else {
			MSGLN("Format succ.");
		}
		uffs_PutDevice(dev);
	}

	uffs_close(fd);  // this should fail on signature check !

	return TRUE;
}
/** ren|mv <old> <new> */
static int cmd_ren(int argc, char *argv[])
{
	const char *oldname;
	const char *newname;
	int ret;

	CHK_ARGC(3, 3);

	oldname = argv[1];
	newname = argv[2];

	if ((ret = uffs_rename(oldname, newname)) == 0) {
		MSGLN("Rename from '%s' to '%s' succ.", oldname, newname);
	}
	else {
		MSGLN("Rename from '%s' to '%s' fail!", oldname, newname);
	}

	return ret;
}
Esempio n. 22
0
static URET test_verify_file(const char *file_name)
{
	int fd;
	int ret = U_FAIL;
	unsigned char buf[100];
	int i, pos, len;

	if ((fd = uffs_open(file_name, UO_RDONLY)) < 0) {
		MSGLN("Can't open file %s for read.", file_name);
		goto test_exit;
	}

	pos = 0;
	while (!uffs_eof(fd)) {
		len = uffs_read(fd, buf, sizeof(buf));
		if (len <= 0)
			goto test_failed;
		for (i = 0; i < len; i++) {
			if (buf[i] != (pos++ & 0xFF)) {
				pos--;
				MSGLN("Verify file %s failed at: %d, expect %x but got %x", file_name, pos, pos & 0xFF, buf[i]);
				goto test_failed;
			}
		}
	}

	if (pos != uffs_seek(fd, 0, USEEK_END)) {
		MSGLN("Verify file %s failed. invalid file length.", file_name);
		goto test_failed;
	}

	MSGLN("Verify file %s succ.", file_name);
	ret = U_SUCC;

test_failed:
	uffs_close(fd);

test_exit:

	return ret;
}
/** print block wear-leveling information
 *		wl [<mount>]
 */
static int cmd_wl(int argc, char *argv[])
{
	const char *mount = "/";
	uffs_Device *dev;
	struct uffs_PartitionSt *par;
	uffs_FileEmu *emu;
	int i, max;
	u32 n;

#define NUM_PER_LINE	10

	CHK_ARGC(1, 2);

	if (argc > 1) {
		mount = argv[1];
	}

	dev = uffs_GetDeviceFromMountPoint(mount);
	if (dev == NULL) {
		MSGLN("Can't get device from mount point %s", mount);
		return -1;
	}

	par = &dev->par;
	emu = (uffs_FileEmu *)(dev->attr->_private);
	max = -1;

	for (i = 0; i < par->end - par->start; i++) {
		if ((i % NUM_PER_LINE) == 0) {
			MSG("%04d:", i + par->start);
		}
		n = i + par->start;
		max = (max == -1 ? n :
				(emu->em_monitor_block[n] > emu->em_monitor_block[max] ? n : max)
			   );
		MSG(" %4d", emu->em_monitor_block[n]);
		if (uffs_TreeFindBadNodeByBlock(dev, n))
			MSG("%c", 'x');
		else if (uffs_TreeFindErasedNodeByBlock(dev, n))
			MSG("%c", ' ');
		else
			MSG("%c", '.');
		if (((i + 1) % NUM_PER_LINE) == 0)
			MSG("\n");
	}
	MSG("\n");
	MSG("Total blocks %d, peak erase count %d at block %d\n",
		par->end - par->start, max == -1 ? 0 : emu->em_monitor_block[max], max);

	uffs_PutDevice(dev);

	return 0;
}
/** mkf <file> */
static int cmd_mkf(int argc, char *argv[])
{
	int fd;
	const char *name;
	int oflags = UO_RDWR | UO_CREATE;

	CHK_ARGC(2, 2);

	name = argv[1];
	fd = uffs_open(name, oflags);
	if (fd < 0) {
		MSGLN("Create %s fail, err: %d", name, uffs_get_error());
		return -1;
	}
	else {
		MSGLN("Create %s succ.", name);
		uffs_close(fd);
	}
	
	return 0;
}
Esempio n. 25
0
static int femu_hw_auto_InitFlash(uffs_Device *dev)
{
	struct uffs_StorageAttrSt *attr = dev->attr;

	// now this is a good chance to adjust page data/spare boundary
	if (attr->page_data_size + attr->spare_size != PAGE_FULL_SIZE) {
		MSGLN("This emulator emulates only for page size %d bytes !", PAGE_FULL_SIZE);
		return -1;
	}
	if (attr->spare_size < PAGE_SPARE_SIZE) {
		attr->page_data_size -= (PAGE_SPARE_SIZE - attr->spare_size);
		attr->spare_size = PAGE_SPARE_SIZE;
		MSGLN("Adjust page data/spare boundary to %d/%d", attr->page_data_size, attr->spare_size);
	}

	// and fix ECC size
	attr->ecc_size = RS_ECC_SIZE;
	MSGLN("Adjust ECC size to %d bytes", attr->ecc_size);
	
	return femu_InitFlash(dev);
}
Esempio n. 26
0
static uint8_t PrintStatus(const CLS1_StdIOType *io) {
	uffs_MountTable *m;
	MSGLN("UFFS defined mount points:");
	m = get_flash_mount_table();
	while (m->dev)
	{
		MSGLN("Mount point: %s, start: %d, end: %d",
				m->mount, m->start_block, m->end_block);
		m++;
	}
	MSGLN("mounted list:");
	m = uffs_MtbGetMounted();
	while (m)
	{
		MSGLN("Mount point: %s, start: %d, end: %d",
				m->mount, m->start_block, m->end_block);
		m = m->next;
	}
	MSGLN("unmounted list:");
	m = uffs_MtbGetUnMounted();
	while (m)
	{
		MSGLN("Mount point: %s, start: %d, end: %d",
				m->mount, m->start_block, m->end_block);
		//m->next;
	}

	return ERR_OK;
}
Esempio n. 27
0
static int cmd_dump(int argc, char *argv[])
{
	const char *mount = "/";
	uffs_Device *dev;

	if (argc > 1) {
		mount = argv[1];
	}

	MSGLN("Dumping %s ... ", mount);

	dev = uffs_GetDeviceFromMountPoint(mount);
	if (dev == NULL) {
		MSGLN("Can't get device from mount point.");
	}
	else {
		do_dump_device(dev);
		uffs_PutDevice(dev);
	}

	return 0;
}
Esempio n. 28
0
static int cmd_VerifyFile(int argc, char *argv[])
{
	const char *name;
	UBOOL noecc = U_FALSE;

	if (argc < 2) {
		return CLI_INVALID_ARG;
	}

	name = argv[1];
	if (argc > 2 && strcmp(argv[2], "noecc") == 0) {
		noecc = U_TRUE;
	}

	MSGLN("Check file %s ... ", name);
	if (test_verify_file(name, noecc) != U_SUCC) {
		MSGLN("Verify file %s failed.", name);
		return -1;
	}

	return 0;
}
/** ls [<dir>] */
static int cmd_ls(int argc, char *argv[])
{
	uffs_DIR *dirp;
	struct uffs_dirent *ent;
	struct uffs_stat stat_buf;
	int count = 0;
	char buf[MAX_PATH_LENGTH+2];
	const char *name = "/";
	char *sub;
	int ret = 0;

	CHK_ARGC(1, 2);

	if (argc > 1)
		name = argv[1];

	dirp = uffs_opendir(name);
	if (dirp == NULL) {
		MSGLN("Can't open '%s' for list", name);
		ret = -1;
	}
	else {
		MSG("------name-----------size---------serial-----" TENDSTR);
		ent = uffs_readdir(dirp);
		while (ent) {
			MSG("%9s", ent->d_name);
			strcpy(buf, name);
			sub = buf;
			if (name[strlen(name)-1] != '/')
				sub = strcat(buf, "/");
			sub = strcat(sub, ent->d_name);
			if (ent->d_type & FILE_ATTR_DIR) {
				sub = strcat(sub, "/");
				MSG("/  \t<%8d>", CountObjectUnder(sub));
			}
			else {
				uffs_stat(sub, &stat_buf);
				MSG("   \t %8d ", stat_buf.st_size);
			}
			MSG("\t%6d" TENDSTR, ent->d_ino);
			count++;
			ent = uffs_readdir(dirp);
		}
		
		uffs_closedir(dirp);

		MSG("Total: %d objects." TENDSTR, count);
	}

	return ret;
}
/** cat <file> [<offset>] [<size>] */
static int cmd_cat(int argc, char *argv[])
{
	int fd;
	const char *name = NULL;
	char buf[100];
	int start = 0, size = 0, printed = 0, n, len;
	int ret = -1;

	CHK_ARGC(2, 4);

	name = argv[1];

	if ((fd = uffs_open(name, UO_RDONLY)) < 0) {
		MSGLN("Can't open %s", name);
		goto fail;
	}

	if (argc > 2) {
		start = strtol(argv[2], NULL, 10);
		if (argc > 3) size = strtol(argv[3], NULL, 10);
	}

	if (start >= 0)
		uffs_seek(fd, start, USEEK_SET);
	else
		uffs_seek(fd, -start, USEEK_END);

	while (uffs_eof(fd) == 0) {
		len = uffs_read(fd, buf, sizeof(buf) - 1);
		if (len == 0) 
			break;
		if (len > 0) {
			if (size == 0 || printed < size) {
				n = (size == 0 ? len : (size - printed > len ? len : size - printed));
				buf[n] = 0;
				MSG("%s", buf);
				printed += n;
			}
			else {
				break;
			}
		}
	}
	MSG(TENDSTR);
	uffs_close(fd);

	ret = 0;
fail:

	return ret;
}