xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/src/emu/test_cmds.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2   This file is part of UFFS, the Ultra-low-cost Flash File System.
3 
4   Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
5 
6   UFFS is free software; you can redistribute it and/or modify it under
7   the GNU Library General Public License as published by the Free Software
8   Foundation; either version 2 of the License, or (at your option) any
9   later version.
10 
11   UFFS is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   or GNU Library General Public License, as applicable, for more details.
15 
16   You should have received a copy of the GNU General Public License
17   and GNU Library General Public License along with UFFS; if not, write
18   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19   Boston, MA  02110-1301, USA.
20 
21   As a special exception, if other files instantiate templates or use
22   macros or inline functions from this file, or you compile this file
23   and link it with other works to produce a work based on this file,
24   this file does not by itself cause the resulting work to be covered
25   by the GNU General Public License. However the source code for this
26   file must still be made available in accordance with section (3) of
27   the GNU General Public License v2.
28 
29   This exception does not invalidate any other reasons why a work based
30   on this file might be covered by the GNU General Public License.
31 */
32 
33 /**
34  * \file test_cmds.c
35  * \brief commands for test uffs
36  * \author Ricky Zheng
37  */
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include "uffs_config.h"
42 #include "uffs/uffs_public.h"
43 #include "uffs/uffs_fd.h"
44 #include "uffs/uffs_utils.h"
45 #include "uffs/uffs_core.h"
46 #include "uffs/uffs_mtb.h"
47 #include "uffs/uffs_find.h"
48 #include "uffs/uffs_badblock.h"
49 #include "cmdline.h"
50 #include "api_test.h"
51 
52 #define PFX "test: "
53 
54 #define	MAX_TEST_BUF_LEN	8192
55 
56 #define SEQ_INIT	10
57 #define SEQ_MOD_LEN	120
58 
59 #define MSG(msg,...) uffs_PerrorRaw(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
60 #define MSGLN(msg,...) uffs_Perror(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
61 
62 
memcp_seq(void * des,int size,int start_pos)63 static void memcp_seq(void *des, int size, int start_pos)
64 {
65 	int i;
66 	u8 *p = (u8 *)des;
67 
68 	for (i = 0; i < size; i++, p++) {
69 		*p = (start_pos + SEQ_INIT + i) % SEQ_MOD_LEN;
70 	}
71 }
72 
check_entry_exist(const char * name)73 static UBOOL check_entry_exist(const char *name)
74 {
75 	struct uffs_stat sb;
76 
77 	return uffs_stat(name, &sb) < 0 ? U_FALSE : U_TRUE;
78 }
79 
do_write_test_file(int fd,int size)80 static URET do_write_test_file(int fd, int size)
81 {
82 	long pos;
83 	unsigned char buf[100];
84 	int len;
85 
86 	while (size > 0) {
87 		pos = uffs_seek(fd, 0, USEEK_CUR);
88 		len = (size > sizeof(buf) ? sizeof(buf) : size);
89 		memcp_seq(buf, len, pos);
90 		if (uffs_write(fd, buf, len) != len) {
91 			MSGLN("Write file failed, size %d at %d", len, pos);
92 			return U_FAIL;
93 		}
94 		size -= len;
95 	}
96 
97 	return U_SUCC;
98 }
99 
test_write_file(const char * file_name,int pos,int size)100 static URET test_write_file(const char *file_name, int pos, int size)
101 {
102 	int ret = U_FAIL;
103 	int fd = -1;
104 
105 	if ((fd = uffs_open(file_name, UO_RDWR|UO_CREATE)) < 0) {
106 		MSGLN("Can't open file %s for write.", file_name);
107 		goto test_exit;
108 	}
109 
110 	if (uffs_seek(fd, pos, USEEK_SET) != pos) {
111 		MSGLN("Can't seek file %s at pos %d", file_name, pos);
112 		goto test_failed;
113 	}
114 
115 	if (do_write_test_file(fd, size) == U_FAIL) {
116 		MSGLN("Write file %s failed.", file_name);
117 		goto test_failed;
118 	}
119 	ret = U_SUCC;
120 
121 test_failed:
122 	uffs_close(fd);
123 
124 test_exit:
125 
126 	return ret;
127 }
128 
129 
test_verify_file(const char * file_name,UBOOL noecc)130 static URET test_verify_file(const char *file_name, UBOOL noecc)
131 {
132 	int fd;
133 	int ret = U_FAIL;
134 	unsigned char buf[100];
135 	int i, pos, len;
136 	u8 x;
137 
138 	if ((fd = uffs_open(file_name, (noecc ? UO_RDONLY|UO_NOECC : UO_RDONLY))) < 0) {
139 		MSGLN("Can't open file %s for read.", file_name);
140 		goto test_exit;
141 	}
142 
143 	pos = 0;
144 	while (!uffs_eof(fd)) {
145 		len = uffs_read(fd, buf, sizeof(buf));
146 		if (len <= 0)
147 			goto test_failed;
148 		for (i = 0; i < len; i++) {
149 			x = (SEQ_INIT + pos + i) % SEQ_MOD_LEN;
150 			if (buf[i] != x) {
151 				MSGLN("Verify file %s failed at: %d, expect 0x%02x but got 0x%02x", file_name, pos + i, x, buf[i]);
152 				goto test_failed;
153 			}
154 		}
155 		pos += len;
156 	}
157 
158 	if (pos != uffs_seek(fd, 0, USEEK_END)) {
159 		MSGLN("Verify file %s failed. invalid file length.", file_name);
160 		goto test_failed;
161 	}
162 
163 	MSGLN("Verify file %s succ.", file_name);
164 	ret = U_SUCC;
165 
166 test_failed:
167 	uffs_close(fd);
168 
169 test_exit:
170 
171 	return ret;
172 }
173 
test_append_file(const char * file_name,int size)174 static URET test_append_file(const char *file_name, int size)
175 {
176 	int ret = U_FAIL;
177 	int fd = -1;
178 
179 	if ((fd = uffs_open(file_name, UO_RDWR|UO_APPEND|UO_CREATE)) < 0) {
180 		MSGLN("Can't open file %s for append.", file_name);
181 		goto test_exit;
182 	}
183 
184 	uffs_seek(fd, 0, USEEK_END);
185 
186 	if (do_write_test_file(fd, size) == U_FAIL) {
187 		MSGLN("Write file %s failed.", file_name);
188 		goto test_failed;
189 	}
190 	ret = U_SUCC;
191 
192 test_failed:
193 	uffs_close(fd);
194 
195 test_exit:
196 
197 	return ret;
198 }
199 
200 
201 /* test create file, write file and read back */
cmd_t1(int argc,char * argv[])202 static int cmd_t1(int argc, char *argv[])
203 {
204 	int fd;
205 	URET ret;
206 	char buf[100];
207 	const char *name;
208 
209 	if (argc < 2) {
210 		return CLI_INVALID_ARG;
211 	}
212 
213 	name = argv[1];
214 
215 	fd = uffs_open(name, UO_RDWR|UO_CREATE|UO_TRUNC);
216 	if (fd < 0) {
217 		MSGLN("Can't open %s", name);
218 		goto fail;
219 	}
220 
221 	sprintf(buf, "123456789ABCDEF");
222 	ret = uffs_write(fd, buf, strlen(buf));
223 	MSGLN("write %d bytes to file, content: %s", ret, buf);
224 
225 	ret = uffs_seek(fd, 3, USEEK_SET);
226 	MSGLN("new file position: %d", ret);
227 
228 	memset(buf, 0, sizeof(buf));
229 	ret = uffs_read(fd, buf, 5);
230 	MSGLN("read %d bytes, content: %s", ret, buf);
231 
232 	uffs_close(fd);
233 
234 	return 0;
235 fail:
236 
237 	return -1;
238 }
239 
240 
DoTest2(void)241 static URET DoTest2(void)
242 {
243 	int fd = -1;
244 	URET ret = U_FAIL;
245 	char buf[100], buf_1[100];
246 
247 	fd = uffs_open("/abc/", UO_RDWR|UO_DIR);
248 	if (fd < 0) {
249 		MSGLN("Can't open dir abc, err: %d", uffs_get_error());
250 		MSGLN("Try to create a new one...");
251 		fd = uffs_open("/abc/", UO_RDWR|UO_CREATE|UO_DIR);
252 		if (fd < 0) {
253 			MSGLN("Can't create new dir /abc/");
254 			goto exit_test;
255 		}
256 		else {
257 			uffs_close(fd);
258 		}
259 	}
260 	else {
261 		uffs_close(fd);
262 	}
263 
264 	fd = uffs_open("/abc/test.txt", UO_RDWR|UO_CREATE);
265 	if (fd < 0) {
266 		MSGLN("Can't open /abc/test.txt");
267 		goto exit_test;
268 	}
269 
270 	sprintf(buf, "123456789ABCDEF");
271 	ret = uffs_write(fd, buf, strlen(buf));
272 	MSGLN("write %d bytes to file, content: %s", ret, buf);
273 
274 	ret = uffs_seek(fd, 3, USEEK_SET);
275 	MSGLN("new file position: %d", ret);
276 
277 	memset(buf_1, 0, sizeof(buf_1));
278 	ret = uffs_read(fd, buf_1, 5);
279 	MSGLN("read %d bytes, content: %s", ret, buf_1);
280 
281 	if (memcmp(buf + 3, buf_1, 5) != 0) {
282 		ret = U_FAIL;
283 	}
284 	else {
285 		ret = U_SUCC;
286 	}
287 
288 	uffs_close(fd);
289 
290 exit_test:
291 
292 	return ret;
293 }
294 
295 
cmd_t2(int argc,char * argv[])296 static int cmd_t2(int argc, char *argv[])
297 {
298 	URET ret;
299 	MSGLN("Test return: %s !", (ret = DoTest2()) == U_SUCC ? "succ" : "failed");
300 
301 	return (ret == U_SUCC) ? 0 : -1;
302 }
303 
304 
cmd_VerifyFile(int argc,char * argv[])305 static int cmd_VerifyFile(int argc, char *argv[])
306 {
307 	const char *name;
308 	UBOOL noecc = U_FALSE;
309 
310 	if (argc < 2) {
311 		return CLI_INVALID_ARG;
312 	}
313 
314 	name = argv[1];
315 	if (argc > 2 && strcmp(argv[2], "noecc") == 0) {
316 		noecc = U_TRUE;
317 	}
318 
319 	MSGLN("Check file %s ... ", name);
320 	if (test_verify_file(name, noecc) != U_SUCC) {
321 		MSGLN("Verify file %s failed.", name);
322 		return -1;
323 	}
324 
325 	return 0;
326 }
327 
328 /* Test file append and 'random' write */
cmd_t3(int argc,char * argv[])329 static int cmd_t3(int argc, char *argv[])
330 {
331 	const char *name;
332 	int i;
333 	UBOOL noecc = U_FALSE;
334 	int write_test_seq[] = { 20, 10, 500, 40, 1140, 900, 329, 4560, 352, 1100 };
335 
336 	if (argc < 2) {
337 		return CLI_INVALID_ARG;
338 	}
339 
340 	name = argv[1];
341 	if (argv[2] && strcmp(argv[2], "noecc") == 0) {
342 		noecc = U_TRUE;
343 	}
344 
345 	if (check_entry_exist(name)) {
346 		MSGLN("Check file %s ... ", name);
347 		if (test_verify_file(name, noecc) != U_SUCC) {
348 			MSGLN("Verify file %s failed.", name);
349 			return -1;
350 		}
351 	}
352 
353 	MSGLN("Test append file %s ...", name);
354 	for (i = 1; i < 500; i += 29) {
355 		if (test_append_file(name, i) != U_SUCC) {
356 			MSGLN("Append file %s test failed at %d !", name, i);
357 			return -1;
358 		}
359 	}
360 
361 	MSGLN("Check file %s ... ", name);
362 	if (test_verify_file(name, noecc) != U_SUCC) {
363 		MSGLN("Verify file %s failed.", name);
364 		return -1;
365 	}
366 
367 	MSGLN("Test write file ...");
368 	for (i = 0; i < sizeof(write_test_seq) / sizeof(int) - 1; i++) {
369 		if (test_write_file(name, write_test_seq[i], write_test_seq[i+1]) != U_SUCC) {
370 			MSGLN("Test write file failed !");
371 			return -1;
372 		}
373 	}
374 
375 	MSGLN("Check file %s ... ", name);
376 	if (test_verify_file(name, noecc) != U_SUCC) {
377 		MSGLN("Verify file %s failed.", name);
378 		return -1;
379 	}
380 
381 	MSGLN("Test succ !");
382 
383 	return 0;
384 }
385 
386 /* open two files and test write */
cmd_t4(int argc,char * argv[])387 static int cmd_t4(int argc, char *argv[])
388 {
389 	int fd1 = -1, fd2 = -1;
390 
391 	MSGLN("open /a ...");
392 	if ((fd1 = uffs_open("/a", UO_RDWR | UO_CREATE)) < 0) {
393 		MSGLN("Can't open /a");
394 		goto fail_exit;
395 	}
396 
397 	MSGLN("open /b ...");
398 	if ((fd2 = uffs_open("/b", UO_RDWR | UO_CREATE)) < 0) {
399 		MSGLN("Can't open /b");
400 		uffs_close(fd1);
401 		goto fail_exit;
402 	}
403 
404 	MSGLN("write (1) to /a ...");
405 	uffs_write(fd1, "Hello,", 6);
406 	MSGLN("write (1) to /b ...");
407 	uffs_write(fd2, "Hello,", 6);
408 	MSGLN("write (2) to /a ...");
409 	uffs_write(fd1, "World.", 6);
410 	MSGLN("write (2) to /b ...");
411 	uffs_write(fd2, "World.", 6);
412 	MSGLN("close /a ...");
413 	uffs_close(fd1);
414 	MSGLN("close /b ...");
415 	uffs_close(fd2);
416 
417 	return 0;
418 
419 fail_exit:
420 	return -1;
421 }
422 
423 /* test appending file */
cmd_t5(int argc,char * argv[])424 static int cmd_t5(int argc, char *argv[])
425 {
426 	int fd = -1;
427 	URET ret;
428 	char buf[100];
429 	const char *name;
430 
431 	if (argc < 2) {
432 		return CLI_INVALID_ARG;
433 	}
434 
435 	name = argv[1];
436 
437 	fd = uffs_open(name, UO_RDWR|UO_APPEND);
438 	if (fd < 0) {
439 		MSGLN("Can't open %s", name);
440 		goto fail;
441 	}
442 
443 	sprintf(buf, "append test...");
444 	ret = uffs_write(fd, buf, strlen(buf));
445 	if (ret != strlen(buf)) {
446 		MSGLN("write file failed, %d/%d", ret, strlen(buf));
447 		ret = -1;
448 	}
449 	else {
450 		MSGLN("write %d bytes to file, content: %s", ret, buf);
451 		ret = 0;
452 	}
453 
454 	uffs_close(fd);
455 
456 	return ret;
457 fail:
458 	return -1;
459 }
460 
461 
462 /* usage: t_pgrw
463  *
464  * This test case test page read/write
465  */
cmd_TestPageReadWrite(int argc,char * argv[])466 static int cmd_TestPageReadWrite(int argc, char *argv[])
467 {
468 	TreeNode *node = NULL;
469 	uffs_Device *dev;
470 	uffs_Tags local_tag;
471 	uffs_Tags *tag = &local_tag;
472 	int ret;
473 	u16 block;
474 	u16 page;
475 	uffs_Buf *buf = NULL;
476 
477 	u32 i;
478 	int rc = -1;
479 
480 	dev = uffs_GetDeviceFromMountPoint("/");
481 	if (!dev)
482 		goto ext;
483 
484 	buf = uffs_BufClone(dev, NULL);
485 	if (!buf)
486 		goto ext;
487 
488 	node = uffs_TreeGetErasedNode(dev);
489 	if (!node) {
490 		MSGLN("no free block ?");
491 		goto ext;
492 	}
493 
494 	for (i = 0; i < dev->com.pg_data_size; i++) {
495 		buf->data[i] = i & 0xFF;
496 	}
497 
498 	block = node->u.list.block;
499 	page = 1;
500 
501 	TAG_DIRTY_BIT(tag) = TAG_DIRTY;
502 	TAG_VALID_BIT(tag) = TAG_VALID;
503 	TAG_DATA_LEN(tag) = dev->com.pg_data_size;
504 	TAG_TYPE(tag) = UFFS_TYPE_DATA;
505 	TAG_PAGE_ID(tag) = 3;
506 	TAG_PARENT(tag) = 100;
507 	TAG_SERIAL(tag) = 10;
508 	TAG_BLOCK_TS(tag) = 1;
509 	SEAL_TAG(tag);
510 
511 	ret = uffs_FlashWritePageCombine(dev, block, page, buf, tag);
512 	if (UFFS_FLASH_HAVE_ERR(ret)) {
513 		MSGLN("Write page error: %d", ret);
514 		goto ext;
515 	}
516 
517 	ret = uffs_FlashReadPage(dev, block, page, buf, U_FALSE);
518 	if (UFFS_FLASH_HAVE_ERR(ret)) {
519 		MSGLN("Read page error: %d", ret);
520 		goto ext;
521 	}
522 
523 	for (i = 0; i < dev->com.pg_data_size; i++) {
524 		if (buf->data[i] != (i & 0xFF)) {
525 			MSGLN("Data verify fail at: %d", i);
526 			goto ext;
527 		}
528 	}
529 
530 	ret = uffs_FlashReadPageTag(dev, block, page, tag);
531 	if (UFFS_FLASH_HAVE_ERR(ret)) {
532 		MSGLN("Read tag (page spare) error: %d", ret);
533 		goto ext;
534 	}
535 
536 	// verify tag:
537 	if (!TAG_IS_SEALED(tag)) {
538 		MSGLN("not sealed ? Tag verify fail!");
539 		goto ext;
540 	}
541 
542 	if (!TAG_IS_DIRTY(tag)) {
543 		MSGLN("not dirty ? Tag verify fail!");
544 		goto ext;
545 	}
546 
547 	if (!TAG_IS_VALID(tag)) {
548 		MSGLN("not valid ? Tag verify fail!");
549 		goto ext;
550 	}
551 
552 	if (TAG_DATA_LEN(tag) != dev->com.pg_data_size ||
553 		TAG_TYPE(tag) != UFFS_TYPE_DATA ||
554 		TAG_PAGE_ID(tag) != 3 ||
555 		TAG_PARENT(tag) != 100 ||
556 		TAG_SERIAL(tag) != 10 ||
557 		TAG_BLOCK_TS(tag) != 1) {
558 
559 		MSGLN("Tag verify fail!");
560 		goto ext;
561 	}
562 
563 	MSGLN("Page read/write test succ.");
564 	rc = 0;
565 
566 ext:
567 	if (node) {
568 		uffs_FlashEraseBlock(dev, node->u.list.block);
569 		if (HAVE_BADBLOCK(dev))
570 			uffs_BadBlockProcess(dev, node);
571 		else
572 			uffs_TreeInsertToErasedListTail(dev, node);
573 	}
574 
575 	if (dev)
576 		uffs_PutDevice(dev);
577 
578 	if (buf)
579 		uffs_BufFreeClone(dev, buf);
580 
581 	return rc;
582 }
583 
584 /* t_format : test format partition */
cmd_TestFormat(int argc,char * argv[])585 static int cmd_TestFormat(int argc, char *argv[])
586 {
587 	URET ret;
588 	const char *mount = "/";
589 	uffs_Device *dev;
590 	UBOOL force = U_FALSE;
591 	const char *test_file = "/a.txt";
592 	int fd;
593 	int rc = -1;
594 
595 	if (argc > 1) {
596 		mount = argv[1];
597 		if (argc > 2 && strcmp(argv[2], "-f") == 0)
598 			force = U_TRUE;
599 	}
600 
601 	fd = uffs_open(test_file, UO_RDWR | UO_CREATE);
602 	if (fd < 0) {
603 		MSGLN("can't create test file %s", test_file);
604 		goto ext;
605 	}
606 
607 	MSGLN("Formating %s ... ", mount);
608 
609 	dev = uffs_GetDeviceFromMountPoint(mount);
610 	if (dev == NULL) {
611 		MSGLN("Can't get device from mount point.");
612 		goto ext;
613 	}
614 	else {
615 		ret = uffs_FormatDevice(dev, force);
616 		if (ret != U_SUCC) {
617 			MSGLN("Format fail.");
618 		}
619 		else {
620 			MSGLN("Format succ.");
621 			rc = 0;
622 		}
623 		uffs_PutDevice(dev);
624 	}
625 
626 	uffs_close(fd);  // this should fail on signature check !
627 ext:
628 	return rc;
629 }
630 
631 
632 
633 /**
634  * usage: t_pfs <start> <n>
635  *
636  * for example: t_pfs /x/ 100
637  *
638  * This test case performs:
639  *   1) create <n> files under <start>, write full file name as file content
640  *   2) list files under <start>, check files are all listed once
641  *   3) check file content aganist file name
642  *   4) delete files on success
643  */
cmd_TestPopulateFiles(int argc,char * argv[])644 static int cmd_TestPopulateFiles(int argc, char *argv[])
645 {
646 	const char *start = "/";
647 	int count = 80;
648 	int i, fd, num;
649 	char name[128];
650 	char buf[128];
651 	uffs_DIR *dirp;
652 	struct uffs_dirent *ent;
653 	unsigned long bitmap[50] = {0};	// one bit per file, maximu 32*50 = 1600 files
654 	UBOOL succ = U_TRUE;
655 
656 #define SBIT(n) bitmap[(n)/(sizeof(bitmap[0]) * 8)] |= (1 << ((n) % (sizeof(bitmap[0]) * 8)))
657 #define GBIT(n) (bitmap[(n)/(sizeof(bitmap[0]) * 8)] & (1 << ((n) % (sizeof(bitmap[0]) * 8))))
658 
659 	if (argc > 1) {
660 		start = argv[1];
661 		if (argc > 2) {
662 			count = strtol(argv[2], NULL, 10);
663 		}
664 	}
665 
666 	if (count > sizeof(bitmap) * 8)
667 		count = sizeof(bitmap) * 8;
668 
669 	for (i = 0, fd = -1; i < count; i++) {
670 		sprintf(name, "%sFile%03d", start, i);
671 		fd = uffs_open(name, UO_RDWR|UO_CREATE|UO_TRUNC);
672 		if (fd < 0) {
673 			MSGLN("Create file %s failed", name);
674 			break;
675 		}
676 		if (uffs_write(fd, name, strlen(name)) != strlen(name)) { // write full path name to file
677 			MSGLN("Write to file %s failed", name);
678 			uffs_close(fd);
679 			break;
680 		}
681 		uffs_close(fd);
682 	}
683 
684 	if (i < count) {
685 		// not success, need to clean up
686 		for (; i >= 0; i--) {
687 			sprintf(name, "%sFile%03d", start, i);
688 			if (uffs_remove(name) < 0)
689 				MSGLN("Delete file %s failed", name);
690 		}
691 		succ = U_FALSE;
692 		goto ext;
693 	}
694 
695 	MSGLN("%d files created.", count);
696 
697 	// list files
698 	dirp = uffs_opendir(start);
699 	if (dirp == NULL) {
700 		MSGLN("Can't open dir %s !", start);
701 		succ = U_FALSE;
702 		goto ext;
703 	}
704 	ent = uffs_readdir(dirp);
705 	while (ent && succ) {
706 
707 		if (!(ent->d_type & FILE_ATTR_DIR) &&					// not a dir
708 			ent->d_namelen == strlen("File000") &&				// check file name length
709 			memcmp(ent->d_name, "File", strlen("File")) == 0) {	// file name start with "File"
710 
711 			MSGLN("List entry %s", ent->d_name);
712 
713 			num = strtol(ent->d_name + 4, NULL, 10);
714 			if (GBIT(num)) {
715 				// file already listed ?
716 				MSGLN("File %d listed twice !", ent->d_name);
717 				succ = U_FALSE;
718 				break;
719 			}
720 			SBIT(num);
721 
722 			// check file content
723 			sprintf(name, "%s%s", start, ent->d_name);
724 			fd = uffs_open(name, UO_RDONLY);
725 			if (fd < 0) {
726 				MSGLN("Open file %d for read failed !", name);
727 			}
728 			else {
729 				memset(buf, 0, sizeof(buf));
730 				num = uffs_read(fd, buf, sizeof(buf));
731 				if (num != strlen(name)) {
732 					MSGLN("%s Read data length expect %d but got %d !", name, strlen(name), num);
733 					succ = U_FALSE;
734 				}
735 				else {
736 					if (memcmp(name, buf, num) != 0) {
737 						MSGLN("File %s have wrong content '%s' !", name, buf);
738 						succ = U_FALSE;
739 					}
740 				}
741 				uffs_close(fd);
742 			}
743 		}
744 		ent = uffs_readdir(dirp);
745 	}
746 	uffs_closedir(dirp);
747 
748 	// check absent files
749 	for (i = 0; i < count; i++) {
750 		if (GBIT(i) == 0) {
751 			sprintf(name, "%sFile%03d", start, i);
752 			MSGLN("File %s not listed !", name);
753 			succ = U_FALSE;
754 		}
755 	}
756 
757 	// delete files if pass the test
758 	for (i = 0; succ && i < count; i++) {
759 		sprintf(name, "%sFile%03d", start, i);
760 		if (uffs_remove(name) < 0) {
761 			MSGLN("Delete file %s failed", name);
762 			succ = U_FALSE;
763 		}
764 	}
765 
766 ext:
767 	MSGLN("Populate files test %s !", succ ? "SUCC" : "FAILED");
768 	return succ ? 0 : -1;
769 
770 }
771 
772 /**
773  * Open <file> with <oflag>, save fd to $1
774  *
775  *		t_open <oflag> <file>
776  */
cmd_topen(int argc,char * argv[])777 static int cmd_topen(int argc, char *argv[])
778 {
779 	int fd;
780 	const char *name;
781 	char *p;
782 	int oflag = 0;
783 
784 	CHK_ARGC(3, 3);
785 
786 	name = argv[2];
787 	p = argv[1];
788 	while(*p) {
789 		switch(*p++) {
790 		case 'a':
791 			oflag |= UO_APPEND;
792 			break;
793 		case 'c':
794 			oflag |= UO_CREATE;
795 			break;
796 		case 't':
797 			oflag |= UO_TRUNC;
798 			break;
799 		case 'w':
800 			oflag |= UO_RDWR;
801 			break;
802 		case 'r':
803 			oflag |= UO_RDONLY;
804 			break;
805 		}
806 	}
807 
808 	fd = uffs_open(name, oflag);
809 
810 	if (fd >= 0) {
811 		cli_env_set('1', fd);
812 		return 0;
813 	}
814 	else {
815 		return -1;
816 	}
817 }
818 
819 /**
820  * seek file pointer
821  *	t_seek <fd> <offset> [<origin>]
822  * if success, $1 = file position after seek
823  */
cmd_tseek(int argc,char * argv[])824 static int cmd_tseek(int argc, char *argv[])
825 {
826 	int origin = USEEK_SET;
827 	int offset;
828 	int fd;
829 	int ret;
830 
831 	CHK_ARGC(3, 4);
832 
833 	if (sscanf(argv[1], "%d", &fd) != 1 ||
834 		sscanf(argv[2], "%d", &offset) != 1)
835 	{
836 		return CLI_INVALID_ARG;
837 	}
838 
839 	if (argc > 3) {
840 		switch(argv[3][0]) {
841 		case 's':
842 			origin = USEEK_SET;
843 			break;
844 		case 'c':
845 			origin = USEEK_CUR;
846 			break;
847 		case 'e':
848 			origin = USEEK_END;
849 			break;
850 		default:
851 			return CLI_INVALID_ARG;
852 		}
853 	}
854 
855 	ret = uffs_seek(fd, offset, origin);
856 	if (ret >= 0) {
857 		cli_env_set('1', ret);
858 		return 0;
859 	}
860 	else {
861 		return -1;
862 	}
863 }
864 
865 /**
866  * close file
867  *	t_close <fd>
868  */
cmd_tclose(int argc,char * argv[])869 static int cmd_tclose(int argc, char *argv[])
870 {
871 	int fd;
872 
873 	CHK_ARGC(2, 2);
874 
875 	if (sscanf(argv[1], "%d", &fd) == 1) {
876 		return uffs_close(fd);
877 	}
878 	else
879 		return -1;
880 }
881 
882 /**
883  * write file
884  *	t_write <fd> <txt> [..]
885  */
cmd_twrite(int argc,char * argv[])886 static int cmd_twrite(int argc, char *argv[])
887 {
888 	int fd;
889 	int i, len = 0;
890 	int ret = 0;
891 
892 	CHK_ARGC(3, 0);
893 	if (sscanf(argv[1], "%d", &fd) != 1) {
894 		return -1;
895 	}
896 	else {
897 		for (i = 2; i < argc; i++) {
898 			len = strlen(argv[i]);
899 			if (uffs_write(fd, argv[i], len) != len) {
900 				ret = -1;
901 				break;
902 			}
903 		}
904 	}
905 
906 	if (ret == 0)
907 		cli_env_set('1', len);
908 
909 	return ret;
910 }
911 
912 /**
913  * read and check seq file
914  *	t_check_seq <fd> <size>
915  */
cmd_tcheck_seq(int argc,char * argv[])916 static int cmd_tcheck_seq(int argc, char *argv[])
917 {
918 	int fd;
919 	int len, size;
920 	int ret = 0, r_ret = 0;
921 	long pos;
922 	u8 buf[MAX_TEST_BUF_LEN];
923 	int i;
924 	u8 x;
925 
926 	CHK_ARGC(3, 3);
927 
928 	if (sscanf(argv[1], "%d", &fd) != 1) {
929 		return -1;
930 	}
931 
932 	if (sscanf(argv[2], "%d", &len) != 1) {
933 		return -1;
934 	}
935 
936 	pos = uffs_tell(fd);
937 	while (len > 0) {
938 		size = (len > sizeof(buf) ? sizeof(buf) : len);
939 		if ((r_ret = uffs_read(fd, buf, size)) < 0) {
940 			MSGLN("Read fail! fd = %d, size = %d, pos = %ld", fd, size, pos);
941 			ret = -1;
942 			break;
943 		}
944 
945 		// check seq
946 		for (i = 0; i < r_ret; i++) {
947 			x = (pos + SEQ_INIT + i) % SEQ_MOD_LEN;
948 			if (buf[i] != x) {
949 				MSGLN("Check fail! fd = %d, pos = %ld (expect 0x%02x but 0x%02x)\n", fd, pos + i, x, buf[i]);
950 				ret = -1;
951 				break;
952 			}
953 		}
954 
955 		if (ret < 0)
956 			break;
957 
958 		len -= r_ret;
959 		pos += r_ret;
960 	}
961 
962 	return ret;
963 }
964 
965 
966 
967 /**
968  * write random seq to file
969  *	t_write_seq <fd> <size>
970  */
cmd_twrite_seq(int argc,char * argv[])971 static int cmd_twrite_seq(int argc, char *argv[])
972 {
973 	int fd;
974 	int len = 0, size = 0;
975 	long pos = 0;
976 	int ret = 0, w_ret = 0;
977 	u8 buf[MAX_TEST_BUF_LEN];
978 
979 	CHK_ARGC(3, 3);
980 	if (sscanf(argv[1], "%d", &fd) != 1) {
981 		return -1;
982 	}
983 
984 	if (sscanf(argv[2], "%d", &len) != 1) {
985 		return -1;
986 	}
987 
988 	pos = uffs_tell(fd);
989 	while (len > 0) {
990 		size = (len < sizeof(buf) ? len : sizeof(buf));
991 		memcp_seq(buf, size, pos);
992 		if ((w_ret = uffs_write(fd, buf, size)) < 0) {
993 			MSGLN("write fail! fd = %d, size = %d, pos = %ld", fd, size, pos);
994 			ret = -1;
995 			break;
996 		}
997 		pos += w_ret;
998 		len -= w_ret;
999 	}
1000 
1001 	if (ret == 0)
1002 		cli_env_set('1', len);
1003 
1004 	return ret;
1005 }
1006 
1007 
1008 /**
1009  * read and check file
1010  *	t_read <fd> <txt>
1011  */
cmd_tread(int argc,char * argv[])1012 static int cmd_tread(int argc, char *argv[])
1013 {
1014 	int fd;
1015 	int len, n;
1016 	int ret = 0;
1017 	char buf[64];
1018 	char *p;
1019 
1020 	CHK_ARGC(3, 3);
1021 
1022 	if (sscanf(argv[1], "%d", &fd) != 1) {
1023 		return -1;
1024 	}
1025 	else {
1026 		len = strlen(argv[2]);
1027 		n = 0;
1028 		p = argv[2];
1029 		while (n < len) {
1030 			n = (len > sizeof(buf) ? sizeof(buf) : len);
1031 			if (uffs_read(fd, buf, n) != n ||
1032 				memcmp(buf, p, n) != 0) {
1033 				ret = -1;
1034 				break;
1035 			}
1036 			len -= n;
1037 			p += n;
1038 		}
1039 	}
1040 
1041 	return ret;
1042 }
1043 
1044 
do_dump_page(uffs_Device * dev,uffs_Buf * buf)1045 static void do_dump_page(uffs_Device *dev, uffs_Buf *buf)
1046 {
1047 	int i, j;
1048 	const int line = 16;
1049 	struct uffs_MiniHeaderSt *header = (struct uffs_MiniHeaderSt *)buf->header;
1050 	MSG("  header.status = %d\n", header->status);
1051 	if (header->status != 0xFF) {
1052 		for (i = 0; i < 64; i += line) {
1053 			MSG("    ");
1054 			for (j = 0; j < line; j++)
1055 				MSG("%02X ", buf->header[i+j]);
1056 			MSG("\n");
1057 		}
1058 		MSG("\n");
1059 	}
1060 }
1061 
do_dump_tag(uffs_Device * dev,uffs_Tags * tag)1062 static void do_dump_tag(uffs_Device *dev, uffs_Tags *tag)
1063 {
1064 	MSG("  tag sealed: %s\n", TAG_IS_SEALED(tag) ? "yes" : "no");
1065 	if (TAG_IS_GOOD(tag)) {
1066 		if (TAG_IS_DIRTY(tag)) {
1067 			MSG("    block_ts = %d\n", tag->s.block_ts);
1068 			MSG("    type = %d\n", tag->s.type);
1069 			MSG("    dirty = %d\n", tag->s.dirty);
1070 			MSG("    page_id = %d\n", tag->s.page_id);
1071 			MSG("    serial = %d\n", tag->s.serial);
1072 			MSG("    parent = %d\n", tag->s.parent);
1073 			MSG("    data_len = %d\n", tag->s.data_len);
1074 		}
1075 		else {
1076 			MSG("  tag is GOOD but NOT DIRTY !!!???\n");
1077 		}
1078 	}
1079 	else if (TAG_IS_SEALED(tag)) {
1080 		MSG(" tag is INVALID\n");
1081 	}
1082 }
1083 
do_dump_device(uffs_Device * dev)1084 static void do_dump_device(uffs_Device *dev)
1085 {
1086 	URET ret;
1087 	int block, page;
1088 	uffs_Tags tag;
1089 	uffs_Buf *buf;
1090 
1091 	buf = uffs_BufClone(dev, NULL);
1092 	if (buf == NULL) {
1093 		MSGLN("Can't clone buf");
1094 		return;
1095 	}
1096 
1097 	for (block = dev->par.start; block <= dev->par.end; block++) {
1098 		MSG("---- block %d ----\n", block);
1099 		for (page = 0; page < dev->attr->pages_per_block; page++) {
1100 			MSG("  == page %d ==\n", page);
1101 			ret = uffs_FlashReadPage(dev, block, page, buf, U_FALSE);
1102 			if (UFFS_FLASH_HAVE_ERR(ret)) {
1103 				MSG(" !!! Read page failed, ret = %d !!!\n", ret);
1104 			}
1105 			else {
1106 				do_dump_page(dev, buf);
1107 				if (buf->header[0] != 0xFF) {
1108 					ret = uffs_FlashReadPageTag(dev, block, page, &tag);
1109 					if (UFFS_FLASH_HAVE_ERR(ret)) {
1110 						MSG(" !!! Read TAG failed, ret = %d !!!\n", ret);
1111 					}
1112 					else {
1113 						do_dump_tag(dev, &tag);
1114 					}
1115 				}
1116 			}
1117 		}
1118 	}
1119 	uffs_BufFreeClone(dev, buf);
1120 }
1121 
cmd_dump(int argc,char * argv[])1122 static int cmd_dump(int argc, char *argv[])
1123 {
1124 	const char *mount = "/";
1125 	uffs_Device *dev;
1126 
1127 	if (argc > 1) {
1128 		mount = argv[1];
1129 	}
1130 
1131 	MSGLN("Dumping %s ... ", mount);
1132 
1133 	dev = uffs_GetDeviceFromMountPoint(mount);
1134 	if (dev == NULL) {
1135 		MSGLN("Can't get device from mount point.");
1136 	}
1137 	else {
1138 		do_dump_device(dev);
1139 		uffs_PutDevice(dev);
1140 	}
1141 
1142 	return 0;
1143 }
1144 
cmd_apisrv(int argc,char * argv[])1145 static int cmd_apisrv(int argc, char *argv[])
1146 {
1147 	return api_server_start();
1148 }
1149 
1150 static const struct cli_command test_cmds[] =
1151 {
1152     { cmd_t1,					"t1",			"<name>",			"test 1" },
1153     { cmd_t2,					"t2",			NULL,				"test 2" },
1154     { cmd_t3,					"t3",			"<name> [<noecc>]",	"test 3" },
1155     { cmd_t4,					"t4",			NULL,				"test 4" },
1156     { cmd_t5,					"t5",			"<name>",			"test 5" },
1157     { cmd_TestPageReadWrite,	"t_pgrw",		NULL,				"test page read/write" },
1158     { cmd_TestFormat,			"t_format",		NULL,				"test format file system" },
1159 	{ cmd_TestPopulateFiles,	"t_pfs",		"[<start> [<n>]]",	"test populate <n> files under <start>" },
1160 	{ cmd_VerifyFile,			"t_vf",			"<file> [<noecc>]", "verify file" },
1161 
1162 	{ cmd_topen,				"t_open",		"<oflg> <file>",	"open file, fd save to $1", },
1163 	{ cmd_tread,				"t_read",		"<fd> <txt>",		"read <fd> and check against <txt>", },
1164 	{ cmd_tcheck_seq,			"t_check_seq",	"<fd> <size>",		"read seq file <fd> and check", },
1165 	{ cmd_twrite,				"t_write",		"<fd> <txt> [...]",	"write <fd>", },
1166 	{ cmd_twrite_seq,			"t_write_seq",	"<fd> <size>",	"write seq file <fd>", },
1167 	{ cmd_tseek,				"t_seek",		"<fd> <offset> [<origin>]",	"seek <fd> file pointer to <offset> from <origin>", },
1168 	{ cmd_tclose,				"t_close",		"<fd>",				"close <fd>", },
1169 	{ cmd_dump,					"dump",			"<mount>",			"dump <mount>", },
1170 
1171 	{ cmd_apisrv,				"apisrv",		NULL,				"start API test server", },
1172 
1173     { NULL, NULL, NULL, NULL }
1174 };
1175 
1176 static struct cli_commandset test_cmdset = {
1177 	test_cmds,
1178 };
1179 
get_test_cmds()1180 struct cli_commandset * get_test_cmds()
1181 {
1182 	return &test_cmdset;
1183 };
1184 
1185 
1186 
1187